/**
 * 场景树 UI 管理器
 * 负责将 SceneTreeManager 的数据渲染为树形UI
 * 处理用户交互（展开/折叠、选择、可见性切换等）
 */

import * as THREE from 'three';
import { getMaterialLibraryManager } from '../model-library/MaterialLibraryManager.js';
import { logSceneNodeModelInfo } from '../utils/modelLogHelper.js';
import loadingProgressManager from '../utils/loadingProgress.js';

export class SceneTreeUI {
    constructor(containerElement, treeManager, mode = 'edit') {
        this.container = containerElement;
        this.treeManager = treeManager;
        this.expandedNodes = new Set(['root']); // 展开的节点ID集合
        this.mode = mode; // 'edit' 或 'presentation'
        
        // 拖拽相关状态
        this.draggedNode = null;
        this.draggedNodes = null; // 多选拖拽的节点列表
        this.dropTarget = null;
        this.dropPosition = null; // 'before' | 'inside' | 'after'
        this.dragPlaceholder = null;
        
        // F键聚焦目标管理
        this._focusTarget = null; // 当前聚焦目标（可以是节点的object3D或mesh）
        this._focusTargetType = null; // 目标类型：'node' 或 'mesh'
        
        // Mesh编辑模式状态管理
        this._meshOriginalTransforms = new Map(); // 保存当前节点所有mesh的原始transform状态 (uuid -> {position, rotation, scale})
        this._currentMeshEditNode = null; // 当前处于mesh编辑模式的节点
        this._editedNodes = new Set(); // 记录所有被编辑过mesh的节点（用于批量重置）
        
        // 多选状态管理
        this.selectedNodes = []; // 多选节点列表
        this.lastClickedNode = null; // 上次点击的节点（用于Shift范围选择）
        
        // 搜索状态管理
        this.searchKeyword = ''; // 当前搜索关键词
        this.searchMatches = []; // 搜索匹配的节点列表
        
        // Mesh搜索状态管理
        this.meshSearchKeyword = ''; // Mesh搜索关键词
        this.meshSearchMatches = []; // Mesh搜索匹配的结果列表 [{node, mesh, path}]
        this.selectedMeshes = []; // 多选的Mesh列表
        this._meshSearchListenersSetup = false; // 标记是否已绑定Mesh搜索事件监听器
        
        // ⭐ Mesh-Node缓存：优化性能，避免重复遍历查找
        // key: mesh.uuid, value: TreeNode
        this.meshNodeCache = new Map();
        
        // 场景树逐层展开层级计数器
        this.sceneTreeExpandLevel = 0;
        
        // 绑定事件
        this.setupEventListeners();
        this.setupSearchListeners();
        
    }
    
    /**
     * 设置搜索事件监听
     */
    setupSearchListeners() {
        const searchInput = document.getElementById('tree-search-input');
        const clearBtn = document.getElementById('tree-search-clear');
        
        if (!searchInput || !clearBtn) return;
        
        // 实时搜索
        searchInput.addEventListener('input', (e) => {
            this.handleSearch(e.target.value);
        });
        
        // 清除搜索
        clearBtn.addEventListener('click', () => {
            searchInput.value = '';
            this.handleSearch('');
            
            // 清除所有选中状态
            this.clearAllSelection();
            
            searchInput.focus();
        });
        
        // 回车键聚焦到第一个匹配项
        searchInput.addEventListener('keydown', async (e) => {
            if (e.key === 'Enter' && this.searchMatches.length > 0) {
                await this.selectNode(this.searchMatches[0].id);
            }
        });
    }
    
    /**
     * 设置事件监听
     */
    setupEventListeners() {
        // 监听树管理器的事件
        this.treeManager.on('nodeAdded', () => this.refresh());
        this.treeManager.on('nodeRemoved', () => this.refresh());
        this.treeManager.on('nodeMoved', () => this.refresh());
        this.treeManager.on('nodeSelected', ({ node, previousNode }) => this.onNodeSelected(node, previousNode));
        this.treeManager.on('nodeDeselected', ({ previousNode }) => this.clearSelection(previousNode));
        
        // 在容器级别添加全局拖拽事件处理（作为fallback）
        this.container.addEventListener('dragover', (e) => {
            if (!this.draggedNode) return;
            e.preventDefault(); // 允许drop
            // 不再输出日志，避免刷屏
        });
        
        this.container.addEventListener('drop', async (e) => {
            // ===== 检查是否从模型库拖拽模型到场景树空白区域 =====
            if (window.currentDragModelData && !this.draggedNode) {
                e.preventDefault();
                e.stopPropagation();
                
                // 保存模型数据并清除全局变量
                const modelData = { ...window.currentDragModelData };
                window.currentDragModelData = null;
                
                // 立即清理模型库的拖拽状态
                if (window.cleanupModelDrag) {
                    window.cleanupModelDrag();
                }
                
                // 创建新节点并应用模型
                await this.createNodeWithModel(modelData);
                return;
            }
            
            // ===== 原有的场景树节点拖拽逻辑 =====
            if (!this.draggedNode) {
                return;
            }
            e.preventDefault();
            
            const mouseY = e.clientY;
            
            // 检查是否拖拽到树的下方空白区域
            const allNodeElements = this.container.querySelectorAll('.tree-node-content');
            
            let isBottomArea = false;
            
            if (allNodeElements.length > 0) {
                const lastNodeElement = allNodeElements[allNodeElements.length - 1];
                const lastNodeRect = lastNodeElement.getBoundingClientRect();
                
                // 如果鼠标在最后一个节点下方，认为是拖拽到底部
                if (mouseY > lastNodeRect.bottom) {
                    isBottomArea = true;
                }
            }
            
            if (isBottomArea) {
                // 拖到底部空白区域，移动到根节点最后
                const rootNode = this.treeManager.root;
                
                if (this.draggedNodes && this.draggedNodes.length > 1) {
                    // 多节点移动到根节点最后
                    this.moveMultipleNodesTo(this.draggedNodes, rootNode.id, 'inside');
                } else {
                    // 单节点移动
                    const currentParent = this.draggedNode.parent;
                    const isAlreadyLast = currentParent === rootNode && 
                                         rootNode.children[rootNode.children.length - 1] === this.draggedNode;
                    
                    if (!isAlreadyLast) {
                        const success = this.treeManager.moveNode(this.draggedNode.id, rootNode.id, -1);
                        
                        if (success) {
                            this.render();
                            this.notifyTreeChanged();
                        } else {
                            console.error('❌ 节点移动失败');
                        }
                    }
                }
                
                this.removeDragPlaceholder();
                this.clearAllDragOverEffects();
                this.draggedNode = null;
                this.draggedNodes = null;
                this.dropTarget = null;
                this.dropPosition = null;
            } else if (this.dropTarget && this.dropPosition) {
                // 如果有有效的dropTarget和position，说明拖拽过程中经过了节点
                if (this.draggedNodes && this.draggedNodes.length > 1) {
                    // 多节点移动
                    this.moveMultipleNodesTo(this.draggedNodes, this.dropTarget.id, this.dropPosition);
                } else {
                    // 单节点移动
                    this.moveNodeTo(this.draggedNode.id, this.dropTarget.id, this.dropPosition);
                }
                
                this.removeDragPlaceholder();
                this.clearAllDragOverEffects();
                this.draggedNode = null;
                this.draggedNodes = null;
                this.dropTarget = null;
                this.dropPosition = null;
            } else {
                console.warn('⚠️ 拖拽到空白区域，且没有经过任何节点（无法确定目标位置）');
            }
        });
    }
    
    /**
     * 处理搜索
     * @param {string} keyword - 搜索关键词
     */
    handleSearch(keyword) {
        this.searchKeyword = keyword.trim().toLowerCase();
        this.searchMatches = [];
        
        // 更新清除按钮显示
        const clearBtn = document.getElementById('tree-search-clear');
        if (clearBtn) {
            clearBtn.style.display = this.searchKeyword ? 'flex' : 'none';
        }
        
        // 如果有搜索关键词，查找匹配的节点
        if (this.searchKeyword) {
            this.treeManager.traverse(node => {
                if (node.id === 'root') return;
                
                // 检查节点名称是否包含关键词
                if (node.name.toLowerCase().includes(this.searchKeyword)) {
                    this.searchMatches.push(node);
                }
            });
        }
        
        // 重新渲染树
        this.render();
    }
    
    /**
     * 渲染整个树
     */
    render() {
        this.container.innerHTML = '';
        
        // 验证当前选中节点是否仍然有效
        if (this.treeManager.selectedNode) {
            const selectedNodeId = this.treeManager.selectedNode.id;
            if (!this.treeManager.findNodeById(selectedNodeId)) {
                console.warn(`⚠️ 清除无效的选中节点: ${selectedNodeId}`);
                this.treeManager.deselectNode(); // 使用统一的取消选择接口
            }
        }
        
        const rootNode = this.treeManager.root;
        
        if (!rootNode || rootNode.children.length === 0) {
            this.renderEmpty();
            return;
        }
        
        const treeElement = document.createElement('div');
        treeElement.className = 'tree-root';
        
        // 如果有搜索关键词，只渲染匹配的节点（并列展示）
        if (this.searchKeyword && this.searchMatches.length > 0) {
            // 搜索模式：只显示匹配的节点，不考虑层级结构
            this.searchMatches.forEach(node => {
                const nodeElement = this.renderSearchResultNode(node);
                treeElement.appendChild(nodeElement);
            });
        } else if (this.searchKeyword && this.searchMatches.length === 0) {
            // 有搜索但无结果
            const noResultElement = document.createElement('div');
            noResultElement.className = 'tree-search-no-result';
            noResultElement.innerHTML = `
                <div style="padding: 40px 20px; text-align: center;">
                    <div style="font-size: 32px; margin-bottom: 10px; opacity: 0.3;">🔍</div>
                    <div style="color: rgba(255, 255, 255, 0.6); font-size: 13px;">未找到匹配 "${this.searchKeyword}" 的节点</div>
                </div>
            `;
            this.container.appendChild(noResultElement);
            return;
        } else {
            // 正常模式：显示完整的树形结构
            rootNode.children.forEach(child => {
                // 🎥 过滤掉相机节点
                if (child.type === 'camera') return;
                
                const nodeElement = this.renderNode(child);
                treeElement.appendChild(nodeElement);
            });
        }
        
        this.container.appendChild(treeElement);
    }
    
    /**
     * 渲染搜索结果节点（扁平展示，显示路径）
     * @param {TreeNode} node - 节点
     * @returns {HTMLElement} 节点DOM元素
     */
    renderSearchResultNode(node) {
        const nodeElement = document.createElement('div');
        nodeElement.className = 'tree-node search-result-node';
        nodeElement.dataset.nodeId = node.id;
        
        // 节点内容
        const contentElement = document.createElement('div');
        contentElement.className = 'tree-node-content search-match';
        if (node.visible) contentElement.classList.add('visible');
        if (this.treeManager.selectedNode?.id === node.id) {
            contentElement.classList.add('selected');
        }
        
        // 🎯 检查是否为节点组子节点（来自模型层级，不可拖拽）
        const modelComponent = node.components && node.components.find(c => c.type === 'model');
        const isHierarchyChild = modelComponent && modelComponent.fromHierarchy;
        
        // ✨ 标记环境节点
        if (node.id === 'environment') {
            contentElement.classList.add('environment-node');
            contentElement.title = '🔒 环境节点（系统节点，不可删除、不可拖拽，可添加子节点）';
        }
        
        // 🎯 标记节点组子节点
        if (isHierarchyChild) {
            contentElement.classList.add('hierarchy-locked-node');
            contentElement.title = contentElement.title 
                ? contentElement.title + ' | 🔒 节点组子节点（不可拖拽移动）'
                : '🔒 节点组子节点（固定在模型层级中，不可拖拽移动）';
        }
        
        // 不启用拖拽（搜索结果模式）
        
        // 固定缩进（搜索结果不需要层级缩进）
        contentElement.style.paddingLeft = '4px';
        
        // 不显示展开/折叠按钮（搜索结果不需要）
        const toggleElement = document.createElement('div');
        toggleElement.className = 'tree-node-toggle empty';
        
        // 节点图标
        const iconElement = document.createElement('div');
        iconElement.className = 'tree-node-icon';
        iconElement.dataset.type = node.type;
        
        // 节点名称
        const nameElement = document.createElement('div');
        nameElement.className = 'tree-node-name';
        nameElement.textContent = node.name;
        nameElement.title = node.getPath();
        
        // 节点路径（显示在节点名称下方）
        const pathElement = document.createElement('div');
        pathElement.className = 'tree-node-path';
        pathElement.textContent = this.getNodePath(node);
        pathElement.style.cssText = 'font-size: 10px; color: rgba(255, 255, 255, 0.4); margin-left: 24px; margin-top: 2px;';
        
        // 节点操作按钮（根据模式显示）
        const actionsElement = document.createElement('div');
        actionsElement.className = 'tree-node-actions';
        
        // 编辑模式：显示mesh结构按钮
        if (this.mode === 'edit') {
            // Mesh结构按钮（仅对有模型组件或包含mesh数据的节点显示）
            const hasModelComponent = node.components && node.components.some(c => c.type === 'model');
            const hasMeshData = this.nodeHasModel(node); // 🎯 检查节点是否包含mesh数据
            const isFromHierarchy = node.userData && node.userData.fromHierarchy; // 🎯 检查是否来自节点组模型
            const shouldShowMeshBtn = hasModelComponent || hasMeshData || isFromHierarchy || (node.type === 'model' && node.object3D);
            
            if (shouldShowMeshBtn) {
                const meshBtn = document.createElement('button');
                meshBtn.className = 'tree-node-action-btn tree-node-mesh';
                meshBtn.textContent = '🔷';
                meshBtn.title = 'Mesh结构';
                meshBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.showMeshStructure(node);
                };
                actionsElement.appendChild(meshBtn);
            }
            
            // ✨ 环境节点：在操作按钮之前添加锁图标
            if (node.id === 'environment') {
                const lockIcon = document.createElement('span');
                lockIcon.className = 'tree-node-lock-icon';
                lockIcon.textContent = '🔒';
                lockIcon.title = '系统节点，不可删除、不可拖拽';
                actionsElement.appendChild(lockIcon);
            }
        }
        
        // 组装节点内容
        contentElement.appendChild(toggleElement);
        contentElement.appendChild(iconElement);
        contentElement.appendChild(nameElement);
        contentElement.appendChild(actionsElement);
        
        // 节点点击事件（支持多选）
        contentElement.onclick = (e) => {
            this.handleNodeClick(node, e);
        };
        
        nodeElement.appendChild(contentElement);
        
        // 添加路径信息
        nodeElement.appendChild(pathElement);
        
        return nodeElement;
    }
    
    /**
     * 获取节点路径
     * @param {TreeNode} node - 节点
     * @returns {string} 路径字符串
     */
    getNodePath(node) {
        const path = [];
        let current = node.parent;
        
        while (current && current.id !== 'root') {
            path.unshift(current.name);
            current = current.parent;
        }
        
        return path.length > 0 ? path.join(' / ') : '根节点';
    }
    
    /**
     * 渲染单个节点
     */
    renderNode(node, level = 0) {
        const nodeElement = document.createElement('div');
        nodeElement.className = 'tree-node';
        nodeElement.dataset.nodeId = node.id;
        nodeElement.dataset.level = level;
        
        // 节点内容
        const contentElement = document.createElement('div');
        contentElement.className = 'tree-node-content';
        if (node.visible) contentElement.classList.add('visible');
        if (this.treeManager.selectedNode?.id === node.id) {
            contentElement.classList.add('selected');
        }
        
        // 🎯 检查是否为节点组子节点（来自模型层级，不可拖拽）
        const modelComponent = node.components && node.components.find(c => c.type === 'model');
        const isHierarchyChild = modelComponent && modelComponent.fromHierarchy;
        
        // 编辑模式下启用拖拽功能
        if (this.mode === 'edit' && node.id !== 'root') {
            // 环境节点不可拖拽，但需要接受其他节点拖入
            if (node.id === 'environment') {
                contentElement.draggable = false;
                this.setupDragEvents(contentElement, node); // 设置drop事件监听
            } else if (isHierarchyChild) {
                // 🔒 节点组子节点不可拖拽（固定在模型层级中）
                contentElement.draggable = false;
                this.setupDragEvents(contentElement, node); // 仍然设置drop事件，可以接受其他节点拖入
            } else {
                contentElement.draggable = true;
                this.setupDragEvents(contentElement, node);
            }
        }
        
        // ✨ 标记环境节点
        if (node.id === 'environment') {
            contentElement.classList.add('environment-node');
            contentElement.title = '🔒 环境节点（系统节点，不可删除、不可拖拽，可添加子节点）';
        }
        
        // 🎯 标记节点组子节点
        if (isHierarchyChild) {
            contentElement.classList.add('hierarchy-locked-node');
            contentElement.title = contentElement.title 
                ? contentElement.title + ' | 🔒 节点组子节点（不可拖拽移动）'
                : '🔒 节点组子节点（固定在模型层级中，不可拖拽移动）';
        }
        
        // 缩进 - 极简风格，适配深层级
        contentElement.style.paddingLeft = `${level * 10 + 4}px`;
        
        // 展开/折叠按钮
        const toggleElement = document.createElement('div');
        toggleElement.className = 'tree-node-toggle';
        if (node.children.length === 0) {
            toggleElement.classList.add('empty');
        } else if (this.expandedNodes.has(node.id)) {
            toggleElement.classList.add('expanded');
            toggleElement.textContent = '▶';
        } else {
            toggleElement.textContent = '▶';
        }
        toggleElement.onclick = (e) => {
            e.stopPropagation();
            this.toggleNode(node.id);
        };
        
        // 节点图标
        const iconElement = document.createElement('div');
        iconElement.className = 'tree-node-icon';
        iconElement.dataset.type = node.type;
        
        // 节点名称
        const nameElement = document.createElement('div');
        nameElement.className = 'tree-node-name';
        nameElement.textContent = node.name;
        nameElement.title = node.getPath();
        
        // 节点操作按钮（根据模式显示）
        const actionsElement = document.createElement('div');
        actionsElement.className = 'tree-node-actions';
        
        // 编辑模式：显示所有操作按钮
        if (this.mode === 'edit') {
            // Mesh结构按钮（仅对有模型组件或包含mesh数据的节点显示）
            const hasModelComponent = node.components && node.components.some(c => c.type === 'model');
            const hasMeshData = this.nodeHasModel(node); // 🎯 检查节点是否包含mesh数据
            const isFromHierarchy = node.userData && node.userData.fromHierarchy; // 🎯 检查是否来自节点组模型
            const shouldShowMeshBtn = hasModelComponent || hasMeshData || isFromHierarchy || (node.type === 'model' && node.object3D);
            
            if (shouldShowMeshBtn) {
                const meshBtn = document.createElement('button');
                meshBtn.className = 'tree-node-action-btn tree-node-mesh';
                meshBtn.textContent = '🔷';
                meshBtn.title = 'Mesh结构';
                meshBtn.onclick = (e) => {
                    e.stopPropagation();
                    this.showMeshStructure(node);
                };
                actionsElement.appendChild(meshBtn);
            }
            
            // ✨ 环境节点：在操作按钮之前添加锁图标
            if (node.id === 'environment') {
                const lockIcon = document.createElement('span');
                lockIcon.className = 'tree-node-lock-icon';
                lockIcon.textContent = '🔒';
                lockIcon.title = '系统节点，不可删除、不可拖拽';
                actionsElement.appendChild(lockIcon);
            }
            
            // 添加子节点按钮
            const addChildBtn = document.createElement('button');
            addChildBtn.className = 'tree-node-action-btn tree-node-add-child';
            addChildBtn.textContent = '➕';
            addChildBtn.title = '添加子节点';
            addChildBtn.onclick = (e) => {
                e.stopPropagation();
                this.addChildNode(node.id);
            };
            actionsElement.appendChild(addChildBtn);
        }
        // 演示模式：不显示任何操作按钮
        // 在演示模式下，用户只能浏览，不能编辑
        
        // 组装节点内容
        contentElement.appendChild(toggleElement);
        contentElement.appendChild(iconElement);
        contentElement.appendChild(nameElement);
        contentElement.appendChild(actionsElement);
        
        // 节点点击事件（支持多选）
        contentElement.onclick = (e) => {
            this.handleNodeClick(node, e);
        };
        
        // 添加 mouseup 事件处理模型库的拖拽（使用自定义拖拽系统）
        contentElement.addEventListener('mouseup', (e) => {
            // 检查是否从模型库拖拽模型
            if (window.currentDragModelData) {
                e.stopPropagation();
                // 保存模型数据并立即清除全局变量
                const modelData = { ...window.currentDragModelData };
                window.currentDragModelData = null;
                
                // 移除视觉提示
                contentElement.classList.remove('model-drop-target');
                
                // 立即清理模型库的拖拽状态（停止预览跟随）
                if (window.cleanupModelDrag) {
                    window.cleanupModelDrag();
                }
                
                // ✨ 环境节点不允许拖拽模型
                if (node.id === 'environment' || node.type === 'environment') {
                    console.warn('⚠️ 环境节点不允许添加模型');
                    return;
                }
                
                // 🔒 节点组节点不允许更换模型
                const modelComp = node.components && node.components.find(c => c.type === 'model');
                const isHierarchyNode = modelComp && (modelComp.fromHierarchy || modelComp.readonly);
                if (isHierarchyNode) {
                    console.warn('⚠️ 节点组节点不允许更换模型');
                    if (window.showMessage) {
                        window.showMessage('节点组节点的模型由模型库固定，不可更换', 'warning');
                    }
                    return;
                }
                
                // 处理模型绑定
                this.handleModelDropOnNode(node, modelData);
            }
        });
        
        // 添加 mouseover 事件显示拖拽提示
        contentElement.addEventListener('mouseover', (e) => {
            // ✨ 环境节点不显示拖拽提示
            if (node.id === 'environment' || node.type === 'environment') {
                return;
            }
            
            // 🔒 节点组节点不显示拖拽提示
            const modelComp = node.components && node.components.find(c => c.type === 'model');
            const isHierarchyNode = modelComp && (modelComp.fromHierarchy || modelComp.readonly);
            if (isHierarchyNode) {
                return;
            }
            
            if (window.currentDragModelData && !this.draggedNode) {
                contentElement.classList.add('model-drop-target');
            }
        });
        
        // 添加 mouseout 事件移除拖拽提示
        contentElement.addEventListener('mouseout', (e) => {
            if (window.currentDragModelData && !this.draggedNode) {
                // 检查是否真的离开了元素
                if (!contentElement.contains(e.relatedTarget)) {
                    contentElement.classList.remove('model-drop-target');
                }
            }
        });
        
        nodeElement.appendChild(contentElement);
        
        // 子节点容器
        if (node.children.length > 0) {
            const childrenElement = document.createElement('div');
            childrenElement.className = 'tree-node-children';
            if (this.expandedNodes.has(node.id)) {
                childrenElement.classList.add('expanded');
            }
            
            node.children.forEach(child => {
                const childElement = this.renderNode(child, level + 1);
                childrenElement.appendChild(childElement);
            });
            
            nodeElement.appendChild(childrenElement);
        }
        
        return nodeElement;
    }
    
    /**
     * 渲染空状态
     */
    renderEmpty() {
        this.container.innerHTML = `
            <div class="tree-empty">
                <div class="tree-empty-icon">🌲</div>
                <div>场景树为空</div>
                <div style="font-size: 11px; margin-top: 8px; opacity: 0.6;">
                    拖拽模型到场景中添加对象
                </div>
            </div>
        `;
    }
    
    /**
     * 展开/折叠节点
     */
    toggleNode(nodeId) {
        if (this.expandedNodes.has(nodeId)) {
            this.expandedNodes.delete(nodeId);
        } else {
            this.expandedNodes.add(nodeId);
        }
        this.render();
    }
    
    /**
     * 处理节点点击事件（支持Ctrl和Shift多选）
     * @param {TreeNode} node - 被点击的节点
     * @param {MouseEvent} event - 鼠标事件
     */
    async handleNodeClick(node, event) {
        const isCtrlPressed = event.ctrlKey || event.metaKey; // Mac上用metaKey
        const isShiftPressed = event.shiftKey;
        
        if (isCtrlPressed) {
            // Ctrl+点击：多选/取消选择
            this.toggleNodeSelection(node);
        } else if (isShiftPressed && this.lastClickedNode) {
            // Shift+点击：范围选择
            this.selectNodeRange(this.lastClickedNode, node);
        } else {
            // 普通点击：单选
            await this.selectNode(node.id);
        }
    }
    
    /**
     * 切换节点选择状态（Ctrl+点击）
     * @param {TreeNode} node - 节点
     */
    toggleNodeSelection(node) {
        const index = this.selectedNodes.findIndex(n => n.id === node.id);
        
        if (index > -1) {
            // 已选中，取消选择
            this.selectedNodes.splice(index, 1);
        } else {
            // 未选中，添加到选择列表
            this.selectedNodes.push(node);
        }
        
        // 更新上次点击的节点
        this.lastClickedNode = node;
        
        // 更新UI显示
        this.updateMultiSelectionUI();
    }
    
    /**
     * 范围选择节点（Shift+点击）
     * @param {TreeNode} startNode - 起始节点
     * @param {TreeNode} endNode - 结束节点
     */
    selectNodeRange(startNode, endNode) {
        // 获取所有可见节点的扁平列表
        const flatNodes = this.getFlatVisibleNodes();
        
        // 找到起始和结束节点的索引
        const startIndex = flatNodes.findIndex(n => n.id === startNode.id);
        const endIndex = flatNodes.findIndex(n => n.id === endNode.id);
        
        if (startIndex === -1 || endIndex === -1) {
            console.warn('⚠️ 无法进行范围选择：找不到起始或结束节点');
            return;
        }
        
        // 确定选择范围（可以是从上到下或从下到上）
        const min = Math.min(startIndex, endIndex);
        const max = Math.max(startIndex, endIndex);
        
        // 清空当前选择
        this.selectedNodes = [];
        
        // 添加范围内的所有节点
        for (let i = min; i <= max; i++) {
            this.selectedNodes.push(flatNodes[i]);
        }
        
        // 更新UI显示
        this.updateMultiSelectionUI();
    }
    
    /**
     * 获取所有可见节点的扁平列表（按显示顺序）
     * @returns {Array<TreeNode>} 扁平节点列表
     */
    getFlatVisibleNodes() {
        // 如果在搜索模式，返回搜索结果列表
        if (this.searchKeyword && this.searchMatches.length > 0) {
            return this.searchMatches;
        }
        
        // 正常模式：返回可见的树形节点
        const flatNodes = [];
        
        const traverse = (node) => {
            flatNodes.push(node);
            
            // 只遍历展开的节点的子节点
            if (this.expandedNodes.has(node.id) && node.children.length > 0) {
                node.children.forEach(child => traverse(child));
            }
        };
        
        // 从根节点的子节点开始遍历
        const rootNode = this.treeManager.root;
        if (rootNode && rootNode.children) {
            rootNode.children.forEach(child => traverse(child));
        }
        
        return flatNodes;
    }
    
    /**
     * 更新多选UI显示
     */
    updateMultiSelectionUI() {
        // 移除所有选中状态
        this.container.querySelectorAll('.tree-node-content.selected').forEach(el => {
            el.classList.remove('selected');
        });
        
        // 添加选中状态到所有选中的节点
        this.selectedNodes.forEach(node => {
            // 在正常模式和搜索模式下都查找节点元素
            const nodeElement = this.container.querySelector(`[data-node-id="${node.id}"] .tree-node-content`);
            if (nodeElement) {
                nodeElement.classList.add('selected');
            }
        });
        
        // 更新多选信息提示
        this.updateMultiSelectInfo();
        
        // 如果有多个节点选中，显示多选模式的轮廓（只高亮第一个）
        if (this.selectedNodes.length > 0) {
            // 移除旧的轮廓
            this.removeOutlineEffect();
            
            // 为第一个选中的节点添加轮廓
            if (this.selectedNodes[0].object3D) {
                this.addOutlineEffect(this.selectedNodes[0].object3D);
            }
        }
    }
    
    /**
     * 更新多选信息提示（显示在标题栏）
     */
    updateMultiSelectInfo() {
        const infoElement = document.getElementById('multi-select-count');
        const countElement = document.getElementById('selected-count');
        
        if (!infoElement || !countElement) return;
        
        if (this.selectedNodes.length > 1) {
            // 多选模式，显示提示
            countElement.textContent = this.selectedNodes.length;
            infoElement.style.display = 'inline-block';
        } else {
            // 单选或无选择，隐藏提示
            infoElement.style.display = 'none';
        }
    }
    
    /**
     * 清除所有选择
     */
    clearAllSelection() {
        this.selectedNodes = [];
        this.lastClickedNode = null;
        this.updateMultiSelectionUI();
        
        // 移除轮廓
        this.removeOutlineEffect();
        
        // 取消TreeManager的选择
        if (this.treeManager.selectedNode) {
            this.treeManager.deselectNode();
        }
    }
    
    /**
     * 选择节点（由UI触发，如点击场景树节点）
     */
    async selectNode(nodeId) {
        // ⭐ 在选择新节点前，检查材质编辑器是否有未保存的修改
        if (window.rightToolbarManager && window.rightToolbarManager.currentActivePanel === 'material-editor') {
            const materialEditorPanel = window.rightToolbarManager.materialEditorPanel;
            if (materialEditorPanel && materialEditorPanel.hasUnsavedChanges) {
                const canProceed = await materialEditorPanel.checkUnsavedBeforeClose();
                if (!canProceed) {
                    return false; // 用户取消或保存失败，不选择节点
                }
                // 如果用户选择保存或放弃修改，关闭材质编辑器面板
                await window.rightToolbarManager.closePanel('material-editor');
            }
        }
        
        // 清空多选列表
        this.selectedNodes = [];
        
        // 调用TreeManager的selectNode，它会触发nodeSelected事件
        // 事件监听器会自动处理轮廓效果、高亮等
        this.treeManager.selectNode(nodeId);
        
        // 添加到多选列表（单选也视为一个元素的多选）
        const node = this.treeManager.findNodeById(nodeId);
        if (node) {
            this.selectedNodes.push(node);
            this.lastClickedNode = node;
        }
        
        // 更新多选信息提示（单选时会隐藏）
        this.updateMultiSelectInfo();
        
        return true;
    }
    
    /**
     * 节点选中事件处理（统一处理所有选中来源）
     * @param {Object} node - 当前选中的节点
     * @param {Object} previousNode - 之前选中的节点
     */
    onNodeSelected(node, previousNode) {
        
        // 0. 如果节点有模型组件，处理mesh编辑模式状态
        const meshPanel = document.getElementById('mesh-structure-panel');
        if (this.nodeHasModel(node)) {
            // 有模型组件：清理之前的mesh选中状态
            const hasMeshSelected = meshPanel && 
                                   meshPanel.classList.contains('active') && 
                                   meshPanel.querySelector('.mesh-tree-node.selected');
            if (hasMeshSelected) {
                // 清理mesh选中状态
                meshPanel.querySelectorAll('.mesh-tree-node.selected').forEach(n => {
                    n.classList.remove('selected');
                });
            }
        }
        
        // 1. 移除上一个节点的轮廓效果
        if (previousNode) {
            this.removeOutlineEffect();
        }
        
        // 2. 高亮当前节点
        this.highlightNode(node.id);
        
        // 3. 如果Mesh面板打开，检查是否需要退出搜索模式
        if (meshPanel && meshPanel.classList.contains('active')) {
            if (this.meshSearchKeyword) {
                // ⚠️ 先恢复所有mesh的变换（在清空缓存之前）
                if (this._meshOriginalTransforms.size > 0) {
                    this.restoreAllMeshOriginalTransforms(null, false);
                }
                
                // 清空搜索字段
                const meshSearchInput = document.getElementById('mesh-search-input');
                if (meshSearchInput) {
                    meshSearchInput.value = '';
                }
                // 清空搜索关键词和结果
                this.meshSearchKeyword = '';
                this.meshSearchMatches = [];
                this.selectedMeshes = [];
                
                // 隐藏清除按钮
                const clearBtn = document.getElementById('mesh-search-clear');
                if (clearBtn) {
                    clearBtn.style.display = 'none';
                }
            }
        }
        
        // 4. 只有当节点有模型组件时，才更新mesh结构面板
        if (this.nodeHasModel(node)) {
            this.updateMeshStructurePanel(node);
        }
        
        // 5. 为当前节点添加轮廓高亮效果
        if (node.object3D) {
            this.addOutlineEffect(node.object3D);
        }
        
        // 6. 设置F键聚焦目标为节点
        if (node.object3D) {
            this._focusTarget = node.object3D;
            this._focusTargetType = 'node';
        }
    }
    
    /**
     * 高亮显示选中的节点
     */
    highlightNode(nodeId) {
        // 移除所有选中状态
        this.container.querySelectorAll('.tree-node-content.selected').forEach(el => {
            el.classList.remove('selected');
        });
        
        // 展开所有父节点，确保节点可见
        this.expandParentNodes(nodeId);
        
        // 添加选中状态
        const nodeElement = this.container.querySelector(`[data-node-id="${nodeId}"] > .tree-node-content`);
        if (nodeElement) {
            nodeElement.classList.add('selected');
            nodeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        }
    }
    
    /**
     * 展开节点的所有父节点，确保节点在场景树中可见
     * @param {string} nodeId - 节点ID
     */
    expandParentNodes(nodeId) {
        const node = this.treeManager.findNodeById(nodeId);
        if (!node) {
            return;
        }
        
        // 从当前节点开始向上遍历所有父节点
        let currentNode = node.parent;
        const parentsToExpand = [];
        
        while (currentNode) {
            parentsToExpand.push(currentNode.id);
            currentNode = currentNode.parent;
        }
        
        // 展开所有父节点
        let needsRender = false;
        parentsToExpand.forEach(parentId => {
            if (!this.expandedNodes.has(parentId)) {
                this.expandedNodes.add(parentId);
                needsRender = true;
            }
        });
        
        // 如果有节点被展开，重新渲染场景树
        if (needsRender) {
            this.render();
        }
    }
    
    /**
     * 清除节点选中状态（统一的取消选择接口）
     * 
     * ⚠️ 重要：这是取消选择节点的唯一标准清理方法，包含所有必要的清理步骤
     * 
     * 固定清理逻辑（每次取消选择都必须执行）：
     * 1. 移除场景树UI的节点高亮
     * 2. 移除模型的边缘轮廓线
     * 3. 关闭TransformControls（坐标轴）
     * 4. 清除网格线（如果有）
     * 5. 关闭属性面板
     * 6. 清空所有缓存数据（不能有任何残留）
     * 
     * ⚠️ 注意：不应直接调用此方法，应该调用 SceneTreeManager.deselectNode()
     *          该方法会触发 nodeDeselected 事件，然后自动调用此清理方法
     * 
     * @param {Object} previousNode - 之前选中的节点
     */
    clearSelection(previousNode) {
        // 0. 清空多选列表
        this.selectedNodes = [];
        this.lastClickedNode = null;
        
        // 1. 移除场景树中的高亮状态（场景树UI）
        this.container.querySelectorAll('.tree-node-content.selected').forEach(el => {
            el.classList.remove('selected');
        });
        
        // 1.5. 隐藏多选信息提示
        this.updateMultiSelectInfo();
        
        // 2. 移除模型轮廓效果（边缘轮廓线）
        this.removeOutlineEffect();
        
        // 3. 关闭TransformControls（坐标轴）
        const currentScene = window.manager?.getCurrentScene();
        if (!window.manager) {
            console.error('❌ window.manager 未定义');
        } else if (!currentScene) {
            console.error('❌ getCurrentScene() 返回 null');
        } else if (!currentScene.transformControlsManager) {
            console.error('❌ transformControlsManager 不存在');
        } else {
            currentScene.transformControlsManager.detach();
            
            if (currentScene.transformControlsManager.transformControls?.visible) {
                console.error('❌ TransformControls 仍然可见');
            }
        }
        
        // 4. 如果有网格线显示，也要清除
        if (this._wireframeEnabled && previousNode) {
            this.disableWireframe(previousNode);
            const wireframeBtn = document.getElementById('toggleWireframeBtn');
            if (wireframeBtn) {
                wireframeBtn.classList.remove('active');
            }
        }
        
        // 5. 关闭属性面板
        if (window.rightToolbarManager) {
            const transformPanel = window.rightToolbarManager.panels['transform'];
            if (transformPanel && transformPanel.classList.contains('show')) {
                window.rightToolbarManager.closePanel('transform');
            }
        }
        
        // 6. 清空缓存的当前选中节点数据
        // 注意：this.treeManager.selectedNode 已在 SceneTreeManager.deselectNode() 中设置为 null
        
        // 7. 清除F键聚焦目标
        this._focusTarget = null;
        this._focusTargetType = null;
        
        // 8. 清除其他缓存数据
        this._previousNode = null;
        this._currentSelectedMesh = null;
        // ⚠️ 注意：不清空 _currentMeshEditNode！它是mesh模式的独立状态，只能由 exitMeshEditMode() 清空
        // 场景树选中状态与mesh模式是两个独立的系统，不应该相互影响
    }
    
    /**
     * 切换节点可见性
     */
    toggleVisibility(nodeId) {
        const node = this.treeManager.findNodeById(nodeId);
        if (node) {
            node.toggleVisible();
            this.render();
            
            // 立即通知后端保存
            this.notifyTreeChanged();
        }
    }
    
    /**
     * 删除多个选中的节点（批量删除）
     */
    deleteSelectedNodes() {
        if (this.selectedNodes.length === 0) {
            console.warn('⚠️ 没有选中的节点');
            return;
        }
        
        // ✨ 检查是否包含环境节点
        const hasEnvironmentNode = this.selectedNodes.some(n => n.id === 'environment');
        const nodesToDelete = this.selectedNodes.filter(n => n.id !== 'environment');
        
        if (nodesToDelete.length === 0) {
            // 只选中了环境节点
            alert('⚠️ 环境节点是系统节点，不能被删除');
            console.warn('⚠️ 环境节点不能被删除');
            return;
        }
        
        if (hasEnvironmentNode && nodesToDelete.length > 0) {
            // 选中了环境节点和其他节点
            console.log('ℹ️ 环境节点已自动跳过，将删除其他选中的节点');
        }
        
        const nodeCount = nodesToDelete.length;
        const nodeNames = nodesToDelete.map(n => n.name).join('", "');
        
        // 使用自定义确认对话框
        this.showConfirmDialog({
            title: '批量删除节点',
            icon: '🗑',
            message: `确定要删除 ${nodeCount} 个节点 "${nodeNames}" 及其所有子节点吗？`,
            confirmText: '删除',
            confirmClass: 'modal-btn-danger',
            onConfirm: async () => {
                const manager = window._sceneManager;
                const currentSceneId = manager ? manager.getCurrentSceneName() : null;
                
                // 批量删除所有选中的节点（排除环境节点）
                for (const node of nodesToDelete) {
                    // 清理模型引用
                    if (node.modelId && currentSceneId && window.updateModelNodeReferences) {
                        window.updateModelNodeReferences(node.modelId, currentSceneId, node.id, 'remove', node.modelType);
                    }
                    
                    // 递归清理子节点的模型引用
                    if (currentSceneId) {
                        node.traverse((childNode) => {
                            if (childNode.modelId && childNode.id !== node.id && window.updateModelNodeReferences) {
                                window.updateModelNodeReferences(childNode.modelId, currentSceneId, childNode.id, 'remove', childNode.modelType);
                            }
                        });
                    }
                    
                    // 删除节点
                    await this.treeManager.removeNode(node.id);
                }
                
                // 清空选择列表
                this.selectedNodes = [];
                this.lastClickedNode = null;
                
                this.render();
                
                // 立即通知后端保存
                this.notifyTreeChanged();
            }
        });
    }
    
    /**
     * 删除节点
     */
    deleteNode(nodeId) {
        const node = this.treeManager.findNodeById(nodeId);
        if (!node) return;
        
        // ✨ 不能删除环境节点
        if (nodeId === 'environment') {
            console.warn('⚠️ 环境节点不能被删除');
            return;
        }
        
        // 使用自定义确认对话框
        this.showConfirmDialog({
            title: '删除节点',
            icon: '🗑',
            message: `确定要删除节点 "${node.name}" 及其所有子节点吗？`,
            confirmText: '删除',
            confirmClass: 'modal-btn-danger',
            onConfirm: async () => {
                // 获取当前场景ID
                const manager = window._sceneManager;
                const currentSceneId = manager ? manager.getCurrentSceneName() : null;
                
                // ⭐⭐ 清理节点及其子节点的材质引用
                if (currentSceneId && window.materialEditorPanel) {
                    await this.removeMaterialReferencesForNode(node, currentSceneId);
                }
                
                // 如果节点有关联的模型ID，需要更新模型的引用列表
                if (node.modelId && currentSceneId && window.updateModelNodeReferences) {
                    window.updateModelNodeReferences(node.modelId, currentSceneId, node.id, 'remove', node.modelType);
                }
                
                // 递归清理所有子节点的模型引用
                if (currentSceneId) {
                    node.traverse((childNode) => {
                        if (childNode.modelId && childNode.id !== node.id && window.updateModelNodeReferences) {
                            window.updateModelNodeReferences(childNode.modelId, currentSceneId, childNode.id, 'remove', childNode.modelType);
                        }
                    });
                }
                
                await this.treeManager.removeNode(nodeId);
                this.render();
                
                // 立即通知后端保存
                this.notifyTreeChanged();
            }
        });
    }
    
    /**
     * 重命名节点
     */
    renameNode(nodeId) {
        const node = this.treeManager.findNodeById(nodeId);
        if (!node) return;
        
        // 使用自定义输入对话框
        this.showInputDialog({
            title: '重命名节点',
            icon: '✏️',
            message: '请输入新名称:',
            defaultValue: node.name,
            confirmText: '确定',
            onConfirm: (newName) => {
                if (newName && newName.trim() && newName !== node.name) {
                    const trimmedName = newName.trim();
                    node.name = trimmedName;
                    
                    // 同步更新 Three.js 对象的名称
                    if (node.object3D) {
                        node.object3D.name = trimmedName;
                    }
                    
                    this.render();
                    
                    // 立即通知后端保存
                    this.notifyTreeChanged();
                }
            }
        });
    }
    
    /**
     * 显示确认对话框
     */
    showConfirmDialog({ title, icon, message, confirmText = '确定', cancelText = '取消', confirmClass = 'modal-btn-primary', onConfirm, onCancel }) {
        // 创建模态框
        const modal = document.createElement('div');
        modal.className = 'custom-modal';
        
        const content = document.createElement('div');
        content.className = 'modal-content';
        
        // 标题
        const header = document.createElement('div');
        header.className = 'modal-header';
        if (icon) {
            const iconEl = document.createElement('span');
            iconEl.className = 'modal-header-icon';
            iconEl.textContent = icon;
            header.appendChild(iconEl);
        }
        const titleEl = document.createElement('span');
        titleEl.textContent = title;
        header.appendChild(titleEl);
        
        // 内容
        const body = document.createElement('div');
        body.className = 'modal-body';
        const messageEl = document.createElement('div');
        messageEl.className = 'modal-message';
        messageEl.textContent = message;
        body.appendChild(messageEl);
        
        // 底部按钮
        const footer = document.createElement('div');
        footer.className = 'modal-footer';
        
        const cancelBtn = document.createElement('button');
        cancelBtn.className = 'modal-btn modal-btn-secondary';
        cancelBtn.textContent = cancelText;
        cancelBtn.onclick = () => {
            document.body.removeChild(modal);
            if (onCancel) onCancel();
        };
        
        const confirmBtn = document.createElement('button');
        confirmBtn.className = `modal-btn ${confirmClass}`;
        confirmBtn.textContent = confirmText;
        confirmBtn.onclick = () => {
            document.body.removeChild(modal);
            if (onConfirm) onConfirm();
        };
        
        footer.appendChild(cancelBtn);
        footer.appendChild(confirmBtn);
        
        content.appendChild(header);
        content.appendChild(body);
        content.appendChild(footer);
        modal.appendChild(content);
        
        // 点击背景关闭
        modal.onclick = (e) => {
            if (e.target === modal) {
                document.body.removeChild(modal);
                if (onCancel) onCancel();
            }
        };
        
        // ESC 键关闭
        const escHandler = (e) => {
            if (e.key === 'Escape') {
                document.body.removeChild(modal);
                if (onCancel) onCancel();
                document.removeEventListener('keydown', escHandler);
            }
        };
        document.addEventListener('keydown', escHandler);
        
        document.body.appendChild(modal);
        confirmBtn.focus();
    }
    
    /**
     * 显示输入对话框
     */
    showInputDialog({ title, icon, message, defaultValue = '', confirmText = '确定', cancelText = '取消', onConfirm, onCancel }) {
        // 创建模态框
        const modal = document.createElement('div');
        modal.className = 'custom-modal';
        
        const content = document.createElement('div');
        content.className = 'modal-content';
        
        // 标题
        const header = document.createElement('div');
        header.className = 'modal-header';
        if (icon) {
            const iconEl = document.createElement('span');
            iconEl.className = 'modal-header-icon';
            iconEl.textContent = icon;
            header.appendChild(iconEl);
        }
        const titleEl = document.createElement('span');
        titleEl.textContent = title;
        header.appendChild(titleEl);
        
        // 内容
        const body = document.createElement('div');
        body.className = 'modal-body';
        if (message) {
            const messageEl = document.createElement('div');
            messageEl.className = 'modal-message';
            messageEl.textContent = message;
            body.appendChild(messageEl);
        }
        
        const input = document.createElement('input');
        input.type = 'text';
        input.className = 'modal-input';
        input.value = defaultValue;
        body.appendChild(input);
        
        // 底部按钮
        const footer = document.createElement('div');
        footer.className = 'modal-footer';
        
        const cancelBtn = document.createElement('button');
        cancelBtn.className = 'modal-btn modal-btn-secondary';
        cancelBtn.textContent = cancelText;
        cancelBtn.onclick = () => {
            document.body.removeChild(modal);
            if (onCancel) onCancel();
        };
        
        const confirmBtn = document.createElement('button');
        confirmBtn.className = 'modal-btn modal-btn-primary';
        confirmBtn.textContent = confirmText;
        const confirmHandler = () => {
            const value = input.value;
            document.body.removeChild(modal);
            if (onConfirm) onConfirm(value);
        };
        confirmBtn.onclick = confirmHandler;
        
        footer.appendChild(cancelBtn);
        footer.appendChild(confirmBtn);
        
        content.appendChild(header);
        content.appendChild(body);
        content.appendChild(footer);
        modal.appendChild(content);
        
        // 点击背景关闭
        modal.onclick = (e) => {
            if (e.target === modal) {
                document.body.removeChild(modal);
                if (onCancel) onCancel();
            }
        };
        
        // Enter 键确认，ESC 键关闭
        const keyHandler = (e) => {
            if (e.key === 'Enter') {
                confirmHandler();
                document.removeEventListener('keydown', keyHandler);
            } else if (e.key === 'Escape') {
                document.body.removeChild(modal);
                if (onCancel) onCancel();
                document.removeEventListener('keydown', keyHandler);
            }
        };
        document.addEventListener('keydown', keyHandler);
        
        document.body.appendChild(modal);
        input.focus();
        input.select();
    }
    
    /**
     * 逐层展开节点
     */
    expandAll() {
        // 增加展开层级
        this.sceneTreeExpandLevel++;
        
        // 清空展开节点集合（除了根节点）
        this.expandedNodes.clear();
        this.expandedNodes.add('root'); // 保持根节点展开
        
        // 递归函数：展开到指定层级
        const expandToLevel = (node, currentLevel) => {
            if (currentLevel < this.sceneTreeExpandLevel && node.children.length > 0) {
                // 当前层级小于目标层级，展开
                this.expandedNodes.add(node.id);
                // 递归处理子节点
                node.children.forEach(child => {
                    expandToLevel(child, currentLevel + 1);
                });
            }
            // 如果当前层级等于或大于目标层级，不展开（不添加到expandedNodes中）
        };
        
        // 从根节点的子节点开始（level 0）
        if (this.treeManager.root) {
            this.treeManager.root.children.forEach(child => {
                expandToLevel(child, 0);
            });
        }
        
        this.render();
    }
    
    /**
     * 折叠所有节点
     */
    collapseAll() {
        // 重置展开层级计数器
        this.sceneTreeExpandLevel = 0;
        
        this.expandedNodes.clear();
        this.expandedNodes.add('root'); // 保持根节点展开
        this.render();
    }
    
    /**
     * 设置显示模式
     * @param {string} mode - 'edit' 或 'presentation'
     */
    setMode(mode) {
        if (mode !== 'edit' && mode !== 'presentation') {
            console.error('❌ 无效的模式:', mode);
            return;
        }
        
        this.mode = mode;
        this.render();
        
        // 更新面板头部工具栏按钮显示
        this.updateHeaderButtons();
    }
    
    /**
     * 更新面板头部按钮显示
     */
    updateHeaderButtons() {
        const panel = this.container.closest('.side-panel');
        if (!panel) return;
        
        // 根据模式显示/隐藏编辑功能按钮
        const editOnlyButtons = panel.querySelectorAll('.edit-only');
        editOnlyButtons.forEach(btn => {
            if (this.mode === 'presentation') {
                btn.style.display = 'none';
            } else {
                btn.style.display = '';
            }
        });
    }
    
    /**
     * 刷新树显示
     */
    refresh() {
        this.render();
    }
    
    /**
     * 显示加载状态
     */
    showLoading() {
        this.container.innerHTML = '<div class="tree-loading">加载中...</div>';
    }
    
    /**
     * 从JSON数据加载树
     * @param {Object} treeData - 场景树数据
     * @param {Function} onProgress - 进度回调函数
     */
    async loadFromJSON(treeData, onProgress = null) {
        // 重置场景树展开层级计数器
        this.sceneTreeExpandLevel = 0;
        
        await this.treeManager.fromJSON(treeData, null, onProgress);
        this.render();
    }
    
    /**
     * 导出树为JSON
     */
    toJSON() {
        return this.treeManager.toJSON();
    }
    
    /**
     * 通知场景树发生变化，触发保存
     */
    notifyTreeChanged() {
        // 触发自定义事件，通知 app.js 保存场景树
        const event = new CustomEvent('sceneTreeChanged');
        window.dispatchEvent(event);
    }
    
    /**
     * 设置节点的拖拽事件
     */
    setupDragEvents(element, node) {
        // 拖拽开始
        element.addEventListener('dragstart', (e) => {
            // 🔒 双重检查：节点组子节点不可拖拽
            const modelComponent = node.components && node.components.find(c => c.type === 'model');
            const isHierarchyChild = modelComponent && modelComponent.fromHierarchy;
            
            if (isHierarchyChild) {
                console.warn('⚠️ 节点组子节点不可拖拽移动');
                e.preventDefault();
                e.stopPropagation();
                if (window.showMessage) {
                    window.showMessage('节点组子节点不可拖拽移动，其位置由模型层级固定', 'warning');
                }
                return;
            }
            
            this.draggedNode = node;
            
            // 检查是否在多选列表中
            const isInSelection = this.selectedNodes.some(n => n.id === node.id);
            
            if (isInSelection && this.selectedNodes.length > 1) {
                // 🔒 多选拖拽：检查是否包含节点组子节点
                const hasHierarchyChild = this.selectedNodes.some(n => {
                    const mc = n.components && n.components.find(c => c.type === 'model');
                    return mc && mc.fromHierarchy;
                });
                
                if (hasHierarchyChild) {
                    console.warn('⚠️ 多选中包含节点组子节点，无法拖拽');
                    e.preventDefault();
                    e.stopPropagation();
                    if (window.showMessage) {
                        window.showMessage('多选中包含节点组子节点，无法拖拽移动', 'warning');
                    }
                    return;
                }
                
                // 多选拖拽：标记所有选中的节点为拖拽状态
                this.draggedNodes = [...this.selectedNodes];
                
                // 标记所有拖拽节点的UI元素
                this.draggedNodes.forEach(n => {
                    const nodeElement = this.container.querySelector(`[data-node-id="${n.id}"] > .tree-node-content`);
                    if (nodeElement) {
                        nodeElement.classList.add('dragging');
                    }
                });
            } else {
                // 单选拖拽
                this.draggedNodes = [node];
                element.classList.add('dragging');
            }
            
            e.dataTransfer.effectAllowed = 'move';
            e.dataTransfer.setData('text/plain', node.id);
        });
        
        // 拖拽结束
        element.addEventListener('dragend', (e) => {
            // 清除所有拖拽节点的dragging样式
            if (this.draggedNodes && this.draggedNodes.length > 0) {
                this.draggedNodes.forEach(n => {
                    const nodeElement = this.container.querySelector(`[data-node-id="${n.id}"] > .tree-node-content`);
                    if (nodeElement) {
                        nodeElement.classList.remove('dragging');
                    }
                });
            } else {
                element.classList.remove('dragging');
            }
            
            this.removeDragPlaceholder();
            this.clearAllDragOverEffects();
            this.draggedNode = null;
            this.draggedNodes = null;
            this.dropTarget = null;
            this.dropPosition = null;
        });
        
        // 拖拽经过 - 根据位置判断插入方式
        element.addEventListener('dragover', (e) => {
            // ===== 检查是否从模型库拖拽模型到节点 =====
            if (window.currentDragModelData && !this.draggedNode) {
                e.preventDefault();
                e.stopPropagation();
                e.dataTransfer.dropEffect = 'copy';
                // 添加视觉提示
                element.classList.add('model-drop-target');
                return;
            }
            
            // ===== 场景树节点拖拽的原有逻辑 =====
            if (!this.draggedNode || this.draggedNode === node) return;
            
            e.preventDefault();
            e.stopPropagation();
            e.dataTransfer.dropEffect = 'move';
            
            // 不能拖到自己的子节点（需要检查所有拖拽的节点）
            const draggedNodes = this.draggedNodes || [this.draggedNode];
            const cannotDrop = draggedNodes.some(draggedNode => {
                return draggedNode.isAncestorOf(node) || draggedNode === node;
            });
            
            if (cannotDrop) {
                e.dataTransfer.dropEffect = 'none';
                // 清除高亮
                this.clearAllDragOverEffects();
                this.removeDragPlaceholder();
                return;
            }
            
            // 根据鼠标位置判断插入位置（三分法）
            const rect = element.getBoundingClientRect();
            const mouseY = e.clientY;
            const relativeY = mouseY - rect.top;
            const height = rect.height;
            
            let position;
            if (relativeY < height * 0.33) {
                position = 'before'; // 上方1/3 - 插入到目标之前
            } else if (relativeY > height * 0.67) {
                position = 'after';  // 下方1/3 - 插入到目标之后
            } else {
                position = 'inside'; // 中间1/3 - 作为子节点
            }
            
            // ⭐ 禁止将节点拖到环境节点之前
            if (node.id === 'environment' && position === 'before') {
                e.dataTransfer.dropEffect = 'none';
                // 清除高亮
                this.clearAllDragOverEffects();
                this.removeDragPlaceholder();
                return;
            }
            
            // 更新拖拽目标和位置
            const targetChanged = this.dropTarget !== node || this.dropPosition !== position;
            if (targetChanged) {
                this.dropTarget = node;
                this.dropPosition = position;
                
                // 更新高亮效果 - 高亮最终的父节点
                this.clearAllDragOverEffects();
                
                // 根据位置确定最终父节点并高亮
                let finalParent = null;
                if (position === 'inside') {
                    // 插入到内部，最终父节点就是目标节点
                    finalParent = node;
                } else {
                    // before/after，最终父节点是目标节点的父节点
                    finalParent = node.parent;
                }
                
                // 高亮最终父节点
                if (finalParent && finalParent.id !== 'root') {
                    const parentElement = this.container.querySelector(`[data-node-id="${finalParent.id}"] > .tree-node-content`);
                    if (parentElement) {
                        parentElement.classList.add('drag-over');
                    }
                }
                
                // 显示插入位置占位符
                this.showDragPlaceholder(element, position);
            }
        });
        
        // 拖拽进入
        element.addEventListener('dragenter', (e) => {
            // 检查是否从模型库拖拽模型
            if (window.currentDragModelData && !this.draggedNode) {
                e.preventDefault();
                return;
            }
            
            // 场景树节点拖拽
            if (!this.draggedNode || this.draggedNode === node) return;
            e.preventDefault();
        });
        
        // 拖拽离开
        element.addEventListener('dragleave', (e) => {
            // 移除模型拖拽的视觉提示
            if (window.currentDragModelData && !this.draggedNode) {
                // 检查是否真的离开了元素（不是进入子元素）
                if (!element.contains(e.relatedTarget)) {
                    element.classList.remove('model-drop-target');
                }
            }
        });
        
        // 放置
        element.addEventListener('drop', (e) => {
            e.preventDefault();
            
            // ===== 检查是否从模型库拖拽模型到节点 =====
            if (window.currentDragModelData && !this.draggedNode) {
                e.stopPropagation();
                
                // 移除视觉提示
                element.classList.remove('model-drop-target');
                
                // 保存模型数据并立即清除全局变量，防止被模型库的 onDragEnd 消费
                const modelData = { ...window.currentDragModelData };
                window.currentDragModelData = null;

                // ✨ 环境节点不允许拖拽模型
                if (node.id === 'environment' || node.type === 'environment') {
                    console.warn('⚠️ 环境节点不允许添加模型');
                    return;
                }
                
                // 🔒 节点组节点不允许更换模型
                const modelComp = node.components && node.components.find(c => c.type === 'model');
                const isHierarchyNode = modelComp && (modelComp.fromHierarchy || modelComp.readonly);
                if (isHierarchyNode) {
                    console.warn('⚠️ 节点组节点不允许更换模型');
                    if (window.showMessage) {
                        window.showMessage('节点组节点的模型由模型库固定，不可更换', 'warning');
                    }
                    return;
                }

                this.handleModelDropOnNode(node, modelData);
                return;
            }
            
            // ===== 原有的场景树节点拖拽逻辑 =====
            const mouseY = e.clientY;
            
            // 检查是否拖拽到底部空白区域
            const allNodeElements = this.container.querySelectorAll('.tree-node-content');
            let isBottomArea = false;
            
            if (allNodeElements.length > 0) {
                const lastNodeElement = allNodeElements[allNodeElements.length - 1];
                const lastNodeRect = lastNodeElement.getBoundingClientRect();
                
                if (mouseY > lastNodeRect.bottom) {
                    isBottomArea = true;
                }
            }
            
            if (isBottomArea) {
                // 拖到底部，移动到根节点最后
                e.stopPropagation(); // 阻止事件继续传播
                
                const rootNode = this.treeManager.root;
                
                if (this.draggedNodes && this.draggedNodes.length > 1) {
                    // 多节点移动到根节点最后
                    this.moveMultipleNodesTo(this.draggedNodes, rootNode.id, 'inside');
                } else {
                    // 单节点移动
                    const currentParent = this.draggedNode.parent;
                    const isAlreadyLast = currentParent === rootNode && 
                                         rootNode.children[rootNode.children.length - 1] === this.draggedNode;
                    
                    if (!isAlreadyLast) {
                        const success = this.treeManager.moveNode(this.draggedNode.id, rootNode.id, -1);
                        if (success) {
                            this.render();
                            this.notifyTreeChanged();
                        }
                    }
                }
                
                this.removeDragPlaceholder();
                this.clearAllDragOverEffects();
                this.draggedNode = null;
                this.draggedNodes = null;
                this.dropTarget = null;
                this.dropPosition = null;
                return;
            }
            
            // 正常的节点drop逻辑
            e.stopPropagation();
            
            if (!this.draggedNode || !this.dropTarget || !this.dropPosition) {
                return;
            }
            
            // 根据位置执行不同的移动操作（支持多节点）
            if (this.draggedNodes && this.draggedNodes.length > 1) {
                // 多节点移动
                this.moveMultipleNodesTo(this.draggedNodes, this.dropTarget.id, this.dropPosition);
            } else {
                // 单节点移动
                this.moveNodeTo(this.draggedNode.id, this.dropTarget.id, this.dropPosition);
            }
            
            this.removeDragPlaceholder();
            this.clearAllDragOverEffects();
            this.draggedNode = null;
            this.draggedNodes = null;
            this.dropTarget = null;
            this.dropPosition = null;
        });
    }
    
    /**
     * 清除所有节点的拖拽高亮效果
     */
    clearAllDragOverEffects() {
        this.container.querySelectorAll('.tree-node-content.drag-over').forEach(el => {
            el.classList.remove('drag-over');
        });
    }
    
    /**
     * 显示拖拽占位符
     * @param {HTMLElement} element - 目标节点元素
     * @param {string} position - 'before' | 'inside' | 'after'
     */
    showDragPlaceholder(element, position) {
        this.removeDragPlaceholder();
        
        this.dragPlaceholder = document.createElement('div');
        this.dragPlaceholder.className = 'tree-drag-placeholder';
        
        const contentElement = element; // element 就是 .tree-node-content
        
        if (position === 'before') {
            // 插入到节点之前
            contentElement.parentElement.insertBefore(this.dragPlaceholder, contentElement);
        } else if (position === 'after') {
            // 插入到节点之后（contentElement 的下一个兄弟之前）
            const nextSibling = contentElement.nextElementSibling;
            if (nextSibling) {
                contentElement.parentElement.insertBefore(this.dragPlaceholder, nextSibling);
            } else {
                contentElement.parentElement.appendChild(this.dragPlaceholder);
            }
        } else if (position === 'inside') {
            // 作为子节点，显示在节点下方（子节点容器内）
            // 不显示占位符，而是通过高亮节点本身来表示
            return;
        }
    }
    
    /**
     * 移除拖拽占位符
     */
    removeDragPlaceholder() {
        if (this.dragPlaceholder && this.dragPlaceholder.parentNode) {
            this.dragPlaceholder.parentNode.removeChild(this.dragPlaceholder);
            this.dragPlaceholder = null;
        }
    }
    
    /**
     * 移动节点到指定位置
     * @param {string} nodeId - 要移动的节点ID
     * @param {string} targetId - 目标节点ID
     * @param {string} position - 'before' | 'inside' | 'after'
     */
    moveNodeTo(nodeId, targetId, position) {
        const node = this.treeManager.findNodeById(nodeId);
        const target = this.treeManager.findNodeById(targetId);
        
        if (!node || !target) return;
        
        // ⭐ 禁止将节点移动到环境节点之前
        if (target.id === 'environment' && position === 'before') {
            console.warn('⚠️ 不能将节点移动到环境节点之前');
            return;
        }
        
        // 检查是否拖拽到当前位置（无需移动的情况）
        if (position === 'inside') {
            // 检查：如果目标就是当前父节点且没有其他移动，无需操作
            if (node.parent === target) {
                return;
            }
        } else if (position === 'before' || position === 'after') {
            // 检查：是否能移动到根节点前后
            const targetParent = target.parent;
            if (!targetParent) {
                console.error('❌ 无法移动到根节点前后');
                return;
            }
            
            // 检查是否拖拽到自己相邻的位置（完全相同的位置）
            if (node.parent === targetParent) {
                const currentIndex = targetParent.children.indexOf(node);
                const targetIndex = targetParent.children.indexOf(target);
                
                // 只有在完全相同的位置才跳过
                if (position === 'before' && currentIndex === targetIndex - 1) {
                    return;
                }
                
                if (position === 'after' && currentIndex === targetIndex + 1) {
                    return;
                }
            }
        }
        
        let success = false;
        let newParent = null;
        let insertIndex = -1;
        
        if (position === 'inside') {
            // 作为目标节点的子节点（添加到最后）
            newParent = target;
            success = this.treeManager.moveNode(nodeId, targetId, -1);
            
            if (success) {
                // 自动展开目标节点
                this.expandedNodes.add(targetId);
            }
        } else if (position === 'before') {
            // 插入到目标节点之前（与目标同级）
            newParent = target.parent;
            const originalTargetIndex = newParent.children.indexOf(target);
            insertIndex = originalTargetIndex;
            
            // 如果节点在目标之前，需要调整索引（因为移除节点后索引会变化）
            if (node.parent === newParent) {
                const currentIndex = newParent.children.indexOf(node);
                
                if (currentIndex < insertIndex) {
                    insertIndex--;
                }
            }
            
            success = this.treeManager.moveNode(nodeId, newParent.id, insertIndex);
            
            if (!success) {
                console.error('❌ 移动失败');
            }
        } else if (position === 'after') {
            // 插入到目标节点之后（与目标同级）
            newParent = target.parent;
            const originalTargetIndex = newParent.children.indexOf(target);
            insertIndex = originalTargetIndex + 1;
            
            // 如果节点在目标之前，需要调整索引
            if (node.parent === newParent) {
                const currentIndex = newParent.children.indexOf(node);
                
                if (currentIndex < insertIndex) {
                    insertIndex--;
                }
            }
            
            success = this.treeManager.moveNode(nodeId, newParent.id, insertIndex);
            
            if (!success) {
                console.error('❌ 移动失败');
            }
        }
        
        if (success) {
            this.render();
            // 通知后端保存
            this.notifyTreeChanged();
        }
    }
    
    /**
     * 移动多个节点到指定位置（保持父子关系）
     * @param {Array<TreeNode>} nodes - 要移动的节点列表
     * @param {string} targetId - 目标节点ID
     * @param {string} position - 位置 ('before' | 'inside' | 'after')
     */
    moveMultipleNodesTo(nodes, targetId, position) {
        if (!nodes || nodes.length === 0) return;
        
        const target = this.treeManager.findNodeById(targetId);
        if (!target) {
            console.error('❌ 目标节点不存在');
            return;
        }
        
        // ⭐ 禁止将节点移动到环境节点之前
        if (target.id === 'environment' && position === 'before') {
            console.warn('⚠️ 不能将节点移动到环境节点之前');
            return;
        }
        
        // 第一步：识别"根节点"（在选中列表中没有父节点的节点）
        // 这些根节点在移动时会带着它们的子节点一起移动
        const nodeSet = new Set(nodes.map(n => n.id));
        const rootNodesToMove = nodes.filter(node => {
            // 检查该节点的父节点是否也在选中列表中
            let parent = node.parent;
            while (parent && parent.id !== 'root') {
                if (nodeSet.has(parent.id)) {
                    // 父节点在选中列表中，这不是根节点
                    return false;
                }
                parent = parent.parent;
            }
            // 父节点不在选中列表中，这是根节点
            return true;
        });
        
        // 第二步：确定目标父节点和插入索引
        let targetParent = null;
        let baseInsertIndex = -1;
        
        if (position === 'inside') {
            // 插入到目标节点内部
            targetParent = target;
            baseInsertIndex = -1; // 添加到最后
        } else if (position === 'before' || position === 'after') {
            // 插入到目标节点前后（与目标同级）
            targetParent = target.parent;
            if (!targetParent) {
                console.error('❌ 无法移动到根节点前后');
                return;
            }
            
            const targetIndex = targetParent.children.indexOf(target);
            baseInsertIndex = position === 'before' ? targetIndex : targetIndex + 1;
        }
        
        // 第三步：收集所有要移动的节点（包括根节点及其所有子孙节点）
        // 这用于检测哪些节点会从当前父节点中移除
        const allNodesBeingMoved = new Set();
        rootNodesToMove.forEach(rootNode => {
            rootNode.traverse(node => {
                allNodesBeingMoved.add(node.id);
            });
        });
        
        // 第四步：如果是before/after，需要调整插入索引
        // 因为移动的节点可能在目标之前，移除后索引会变化
        if (position === 'before' || position === 'after') {
            // 计算有多少个"根节点"在目标之前且会被移除
            let countBeforeTarget = 0;
            for (let i = 0; i < baseInsertIndex; i++) {
                if (targetParent.children[i] && allNodesBeingMoved.has(targetParent.children[i].id)) {
                    countBeforeTarget++;
                }
            }
            baseInsertIndex -= countBeforeTarget;
        }
        
        // 第五步：依次移动每个根节点
        let currentInsertIndex = baseInsertIndex;
        let successCount = 0;
        
        rootNodesToMove.forEach((node, i) => {
            // 检查是否拖拽到当前位置（避免无意义的移动）
            if (position === 'inside') {
                if (node.parent === targetParent) {
                    return;
                }
            }
            
            // 执行移动
            let success = false;
            if (currentInsertIndex === -1) {
                // 添加到最后
                success = this.treeManager.moveNode(node.id, targetParent.id, -1);
            } else {
                // 插入到指定位置
                success = this.treeManager.moveNode(node.id, targetParent.id, currentInsertIndex);
                
                // 如果插入成功，下一个节点插入到当前位置+1
                if (success) {
                    currentInsertIndex++;
                }
            }
            
            if (success) {
                successCount++;
            } else {
                console.error(`   ❌ 移动节点 ${node.name} 失败`);
            }
        });
        
        // 第六步：如果目标是'inside'，自动展开目标节点
        if (position === 'inside' && successCount > 0) {
            this.expandedNodes.add(targetParent.id);
        }
        
        // 第七步：刷新UI和保存
        if (successCount > 0) {
            this.render();
            this.notifyTreeChanged();
        } else {
            console.warn('⚠️ 没有节点被移动');
        }
    }
    
    /**
     * 计算节点的后代数量
     */
    countDescendants(node) {
        let count = 0;
        node.traverse((n) => {
            if (n !== node) count++;
        });
        return count;
    }
    
    /**
     * 添加子节点
     */
    async addChildNode(parentId) {
        const parent = this.treeManager.findNodeById(parentId);
        if (!parent) return;
        
        // 直接创建"空节点"，不弹窗
        const nodeName = '空节点';
        
        // 创建一个空的 THREE.Group 作为容器
        const emptyGroup = new THREE.Group();
        emptyGroup.name = nodeName;
        
        // 创建空节点
        const newNode = this.treeManager.addNode({
            name: nodeName,
            type: 'empty',
            object3D: emptyGroup,
            userData: { isEmpty: true }
        }, parentId);
        
        if (newNode) {
            // 自动展开父节点
            this.expandedNodes.add(parentId);
            
            this.render();
            await this.selectNode(newNode.id);
            
            // 通知后端保存
            this.notifyTreeChanged();
        }
    }
    
    /**
     * 创建新节点并应用模型
     * @param {Object} modelData - 模型数据 {modelId, name, ...}
     */
    async createNodeWithModel(modelData) {
        
        try {
            // 显示进度条
            loadingProgressManager.show();
            loadingProgressManager.setCategoryTotal('model', 1);
            loadingProgressManager.setCategoryTotal('material', 1);
            loadingProgressManager.updateCategoryItem('model', `创建节点: ${modelData.name}`);
            
            // 🎯 从模型库获取模型的完整数据（包含meshMaterials）
            const modelType = modelData.modelType || 'model'; // 🎯 获取模型类型
            const modelLibraryData = await this.getModelLibraryData(modelData.modelId, modelType);
            
            // 创建新节点
            const newNodeData = {
                name: modelData.name || '新模型',
                type: 'model',
                components: [
                    {
                        type: 'model',
                        modelId: modelData.modelId,
                        modelName: modelData.name,
                        modelType: modelType // 🎯 保存模型类型到组件
                    }
                ],
                transform: {
                    position: { x: 0, y: 0, z: 0 },
                    rotation: { x: 0, y: 0, z: 0 },
                    scale: { x: 1, y: 1, z: 1 }
                }
            };
            
            // 从模型库复制meshMaterials数据（验证材质是否存在）
            const modelComponent = newNodeData.components[0];
            modelComponent.meshMaterials = await this.copyMeshMaterialsFromLibrary(modelLibraryData);
            
            // 添加节点到场景树
            const newNode = this.treeManager.addNode(newNodeData);
            if (!newNode) {
                throw new Error('创建节点失败');
            }
            
            // 加载并绑定模型到节点
            await this.loadAndBindModelToNode(newNode, modelData);
            
            // 刷新场景树UI
            this.render();
            
            // 选中新创建的节点
            await this.selectNode(newNode.id);
            
            // 通知后端保存
            this.notifyTreeChanged();
        } catch (error) {
            console.error(`❌ 创建节点失败:`, error);
            loadingProgressManager.hide();
            alert(`创建节点失败: ${error.message}`);
        }
    }

    /**
     * 处理模型拖拽到节点上
     * @param {TreeNode} node - 目标节点
     * @param {Object} modelData - 模型数据 {modelId, modelPath, modelScale, name}
     */
    async handleModelDropOnNode(node, modelData) {
        // ✨ 环境节点不允许拖拽模型
        if (node.id === 'environment' || node.type === 'environment') {
            console.warn('⚠️ 环境节点不允许添加模型');
            return;
        }
        
        // 🔒 节点组节点不允许更换模型（包括根节点和子节点）
        const modelComponent = node.components && node.components.find(c => c.type === 'model');
        const isHierarchyNode = modelComponent && (modelComponent.fromHierarchy || modelComponent.readonly);
        
        if (isHierarchyNode) {
            console.warn('⚠️ 节点组节点不允许更换模型');
            if (window.showMessage) {
                window.showMessage('节点组节点的模型由模型库固定，不可更换', 'warning');
            }
            return;
        }
        
        try {
            // 确保节点有 components 数组
            if (!node.components) {
                node.components = [];
            }
            
            // 检查节点是否已有模型组件
            const existingModelComponent = node.components.find(c => c.type === 'model');
            const isReplacing = !!existingModelComponent;
            
            // 🎯 从模型库获取模型的完整数据（包含meshMaterials）
            const modelType = modelData.modelType || 'model'; // 🎯 获取模型类型
            const modelLibraryData = await this.getModelLibraryData(modelData.modelId, modelType);
            
            if (isReplacing) {
                // 先移除旧模型的 3D 对象
                if (window.transformPanel) {
                    await window.transformPanel.removeModelFromNode(node);
                }
                // 更新模型组件数据（包括材质信息）
                existingModelComponent.modelId = modelData.modelId;
                existingModelComponent.modelName = modelData.name;
                existingModelComponent.modelType = modelType; // 🎯 保存模型类型
                // 从模型库复制meshMaterials数据（验证材质是否存在）
                existingModelComponent.meshMaterials = await this.copyMeshMaterialsFromLibrary(modelLibraryData);
            } else {
                // 添加新的模型组件（包括材质信息）
                const modelComponent = {
                    type: 'model',
                    modelId: modelData.modelId,
                    modelName: modelData.name,
                    modelType: modelType // 🎯 保存模型类型
                };
                // 从模型库复制meshMaterials数据（验证材质是否存在）
                modelComponent.meshMaterials = await this.copyMeshMaterialsFromLibrary(modelLibraryData);
                
                node.components.push(modelComponent);
            }
            
            // ✅ 确保节点的缩放值重置为1（无论是新添加还是替换模型）
            // 不要继承源模型的缩放值（如FBX的0.01），baseScale会在应用时自动乘入
            if (!node.transform) {
                node.transform = {
                    position: { x: 0, y: 0, z: 0 },
                    rotation: { x: 0, y: 0, z: 0 },
                    scale: { x: 1, y: 1, z: 1 }
                };
            } else {
                // 重置缩放为1，保持位置和旋转不变
                node.transform.scale = { x: 1, y: 1, z: 1 };
            }
            // 加载并绑定模型到节点
            await this.loadAndBindModelToNode(node, modelData);
            
            // 更新节点类型
            if (node.type !== 'model') {
                node.type = 'model';
            }
            
            // 刷新场景树UI（更新节点图标）
            this.render();
            
            // 如果有 TransformPanel，刷新它的显示
            if (window.transformPanel && window.transformPanel.currentNode === node) {
                window.transformPanel.renderComponents(node);
                // ✅ 同时更新transform输入框的值，确保缩放显示为1
                window.transformPanel.updateInputValues();
            }
            
            // 选中该节点
            await this.selectNode(node.id);
            
            // 通知后端保存
            this.notifyTreeChanged();
        } catch (error) {
            console.error(`❌ 处理模型拖拽失败:`, error);
            alert(`加载模型失败: ${error.message}`);
        }
    }
    
    /**
     * 从模型库获取模型的完整数据
     * @param {string} modelId - 模型ID
     * @returns {Promise<Object>} 模型数据
     */
    async getModelLibraryData(modelId, modelType = 'model') {
        try {
            const currentProject = window.projectManager?.getCurrentProject();
            if (!currentProject) {
                console.warn('⚠️ 无法获取当前项目');
                return null;
            }
            
            // 🎯 添加 type 参数以支持节点模型
            const typeParam = modelType === 'node' ? '?type=node' : '';
            const response = await fetch(`/api/projects/${currentProject.id}/models/${modelId}${typeParam}`);
            if (!response.ok) {
                console.warn(`⚠️ 获取模型数据失败: ${response.status}`);
                return null;
            }
            
            const result = await response.json();
            if (result.success && result.data) {
                return result.data;
            }
            
            return null;
        } catch (error) {
            console.error('❌ 获取模型库数据失败:', error);
            return null;
        }
    }

    /**
     * 从模型库数据中复制meshMaterials（只复制已设置且在材质库存在的材质）
     * @param {Object} modelLibraryData - 模型库数据
     * @returns {Promise<Object>} meshMaterials对象
     */
    async copyMeshMaterialsFromLibrary(modelLibraryData) {
        if (!modelLibraryData || !modelLibraryData.meshMaterials) {
            return {};
        }
        
        // 获取材质库管理器
        const currentProject = window.projectManager?.getCurrentProject();
        if (!currentProject) {
            console.warn('⚠️ 无法获取当前项目，跳过材质验证');
            return {};
        }
        
        const materialLibraryManager = window.materialLibraryManager;
        if (!materialLibraryManager) {
            console.warn('⚠️ 材质库管理器未初始化，跳过材质验证');
            return {};
        }
        
        // 确保材质库已加载
        if (!materialLibraryManager.materials || materialLibraryManager.materials.length === 0) {
            await materialLibraryManager.loadMaterials();
        }
        
        const meshMaterials = {};
        let copiedCount = 0;
        let skippedCount = 0;
        
        // 遍历模型库的meshMaterials
        console.log(`📋 [复制材质绑定] 模型库材质数据:`, modelLibraryData.meshMaterials);
        console.log(`📋 [复制材质绑定] 材质库材质数量: ${materialLibraryManager.materials.length}`);
        console.log(`📋 [复制材质绑定] 材质库材质列表:`, materialLibraryManager.materials.map(m => m.displayName));
        
        for (const [meshId, materialName] of Object.entries(modelLibraryData.meshMaterials)) {
            if (!materialName || typeof materialName !== 'string') {
                console.warn(`   ⚠️ Mesh "${meshId}" 没有有效的材质名`);
                skippedCount++;
                continue;
            }
            
            // 检查材质在材质库中是否存在（按 displayName 查找）
            const materialExists = materialLibraryManager.materials.some(
                mat => mat.displayName === materialName
            );
            
            if (materialExists) {
                // ✅ 材质存在，直接赋值材质名
                meshMaterials[meshId] = materialName;
                copiedCount++;
            } else {
                // 材质不存在，跳过
                skippedCount++;
                console.warn(`   ⚠️ 跳过材质绑定 (材质不存在): Mesh "${meshId}" → 材质 "${materialName}"`);
            }
        }
        
        console.log(`📊 [复制材质绑定] 结果: 成功 ${copiedCount} 个，跳过 ${skippedCount} 个`);
        console.log(`📊 [复制材质绑定] 返回数据:`, meshMaterials);
        
        if (skippedCount > 0) {
            console.warn(`⚠️ 跳过了 ${skippedCount} 个材质绑定（材质不存在）`);
        }
        
        return meshMaterials;
    }

    /**
     * 加载并绑定模型到节点
     * @param {TreeNode} node - 目标节点  
     * @param {Object} modelData - 模型数据
     */
    async loadAndBindModelToNode(node, modelData) {
        
        // 更新模型加载状态
        loadingProgressManager.updateCategoryItem('model', `加载: ${node.name}`);
        
        // 获取模型加载器
        const modelLoader = window.modelLoader;
        if (!modelLoader) {
            loadingProgressManager.hide();
            throw new Error('模型加载器未初始化');
        }
        
        // 加载模型
        const loadedObject3D = await modelLoader.loadModelById(modelData.modelId);
        
        if (!loadedObject3D) {
            loadingProgressManager.hide();
            throw new Error('模型加载失败');
        }
        
        // 设置模型名称
        loadedObject3D.name = node.name;
        
        // ✅ 保存模型的原始缩放（如FBX的0.01），仅用于显示调整
        if (!node.originalScale || (node.originalScale.x === 1 && node.originalScale.y === 1 && node.originalScale.z === 1)) {
            node.originalScale = {
                x: loadedObject3D.scale.x,
                y: loadedObject3D.scale.y,
                z: loadedObject3D.scale.z
            };
        }
        
        // 应用节点的 Transform 数据
        this.applyNodeTransformToModel(node, loadedObject3D);
        
        // 获取场景
        const manager = window._sceneManager;
        const currentScene = manager?.getCurrentScene();
        if (!currentScene || !currentScene.scene) {
            throw new Error('当前场景不存在');
        }
        
        // 将模型添加到场景中合适的父对象
        let targetParent = currentScene.scene;
        if (node.parent && node.parent.id !== 'root' && node.parent.object3D) {
            targetParent = node.parent.object3D;
        }
        
        targetParent.add(loadedObject3D);
        // 更新节点的 object3D 引用
        node.object3D = loadedObject3D;
        
        // 同步节点ID到object3D的uuid
        loadedObject3D.uuid = node.id;
        
        // 完成模型加载
        loadingProgressManager.incrementCategory('model');
        
        // 🎨 应用模型库中配置的mesh材质（根据文档第4点要求）
        // 如果模型在上传时配置了mesh材质绑定，这里会应用到场景模型上
        const modelComponent = node.components.find(c => c.type === 'model');
        if (modelComponent && modelComponent.meshMaterials && Object.keys(modelComponent.meshMaterials).length > 0) {
            loadingProgressManager.updateCategoryItem('material', '应用材质绑定');
            
            const currentProject = window.projectManager?.getCurrentProject();
            if (currentProject) {
                try {
                    // ✅ 创建新节点时，需要写入材质引用（isLoadingScene=false，默认值）
                    await this.treeManager.applyMeshMaterials(node, modelComponent, currentProject.id);
                    loadingProgressManager.incrementCategory('material');
                } catch (error) {
                    console.error('❌ 材质应用失败:', error);
                    loadingProgressManager.incrementCategory('material');
                }
            }
        } else {
            // 没有材质绑定，也计数
            loadingProgressManager.incrementCategory('material');
        }
        
        // 📊 输出场景节点模型的详细信息（mesh名、材质ID、参数、贴图名）
        await logSceneNodeModelInfo(loadedObject3D, node, '场景节点');
        
        // 如果节点被选中，附加 TransformControls
        if (this.treeManager.selectedNode === node) {
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.attach(loadedObject3D);
            }
        }
    }
    
    /**
     * 应用节点的 Transform 数据到模型
     * @param {TreeNode} node - 节点
     * @param {THREE.Object3D} object3D - 3D 对象
     */
    applyNodeTransformToModel(node, object3D) {
        if (!node.transform) {
            console.warn(`⚠️ 节点 "${node.name}" 没有 transform 数据`);
            return;
        }
        
        const t = node.transform;
        
        // 应用位置
        if (t.position) {
            object3D.position.set(
                t.position.x || 0,
                t.position.y || 0,
                t.position.z || 0
            );
        }
        
        // 应用旋转（欧拉角，弧度）
        if (t.rotation) {
            object3D.rotation.set(
                t.rotation.x || 0,
                t.rotation.y || 0,
                t.rotation.z || 0
            );
        }
        
        // 应用缩放
        if (t.scale) {
            // ✅ 使用 originalScale（模型原始缩放）而不是 baseScale
            const originalScale = node.originalScale || { x: 1, y: 1, z: 1 };
            
            // 最终缩放 = 原始缩放 × 节点缩放
            const finalScaleX = originalScale.x * (t.scale.x || 1);
            const finalScaleY = originalScale.y * (t.scale.y || 1);
            const finalScaleZ = originalScale.z * (t.scale.z || 1);
            
            object3D.scale.set(finalScaleX, finalScaleY, finalScaleZ);
        }
        
        // 强制更新矩阵
        object3D.updateMatrix();
        object3D.updateMatrixWorld(true);
    }
    
    /**
     * 检查节点是否有实际的模型组件
     * @param {TreeNode} node - 节点
     * @returns {boolean} 是否有模型
     */
    nodeHasModel(node) {
        if (!node || !node.object3D) {
            return false;
        }
        
        // 检查是否是空Group（只有Group类型且没有实际的mesh子对象）
        if (node.object3D.type === 'Group') {
            // 递归检查是否有Mesh子对象
            let hasMesh = false;
            node.object3D.traverse((child) => {
                if (child.isMesh) {
                    hasMesh = true;
                }
            });
            return hasMesh;
        }
        
        // 如果是Mesh类型或其他有几何体的对象，认为有模型
        return true;
    }
    
    /**
     * 进入Mesh编辑模式（点击mesh按钮时调用）
     * @param {TreeNode} node - 节点
     */
    enterMeshEditMode(node) {
        if (!this.nodeHasModel(node)) {
            console.warn('⚠️ 节点没有mesh数据，无法进入Mesh模式');
            if (window.showMessage) {
                window.showMessage('该节点没有mesh数据', 'warning');
            }
            return;
        }
        
        // ⭐ 使用统一的显示mesh面板方法（内部处理补位逻辑）
        this.showMeshPanel();
        
        this.refreshMeshEditMode(node);
    }
    
    /**
     * 刷新Mesh编辑模式（切换节点、重置时调用）
     * @param {TreeNode} node - 当前节点
     */
    refreshMeshEditMode(node) {
        // ⭐ 清除旧的mesh-node缓存（准备建立新的缓存）
        if (this.meshNodeCache.size > 0) {
            this.meshNodeCache.clear();
        }
        
        // 1. 判断是否为同一个节点
        const isSameNode = this._currentMeshEditNode === node;
        
        // 2. 重置当前/上一个节点的所有mesh位置旋转缩放
        if (this._currentMeshEditNode) {
            // ⚠️ 只有在切换节点时才恢复mesh原始transform
            // 如果是同一个节点（比如在搜索模式下重新渲染），不恢复变换，保持用户的修改
            if (!isSameNode) {
                // 🔧 符合mesh模式文档要求：切换节点时恢复并清空缓存
                this.restoreAllMeshOriginalTransforms(null, true);
            }
            
            // 如果切换节点，重置网格线
            if (!isSameNode && this._wireframeEnabled && this._previousNode) {
                this.disableWireframe(this._previousNode);
                const wireframeBtn = document.getElementById('toggleWireframeBtn');
                if (wireframeBtn) {
                    wireframeBtn.classList.remove('active');
                }
            }
            
            // 如果切换节点，清除搜索模式下的选中状态
            if (!isSameNode && this.selectedMeshes.length > 0) {
                this.selectedMeshes = [];
            }
        }
        
        // 3. 渲染mesh结构（搜索模式或普通模式）
        const meshPanel = document.getElementById('mesh-structure-panel');
        if (meshPanel) {
            const treeContainer = meshPanel.querySelector('.mesh-tree-container');
            
            // 检查是否在搜索模式
            if (this.meshSearchKeyword) {
                // 搜索模式：渲染搜索结果
                this.removeOutlineEffect();
                treeContainer.innerHTML = this.renderMeshSearchResults();
                this.bindMeshSearchSelectionEvents(meshPanel);
            } else if (!isSameNode) {
                // 普通模式且切换节点：渲染当前节点的mesh结构
                this.removeOutlineEffect();
                
                // 解析并渲染mesh结构
                const meshStructure = this.parseMeshStructure(node.object3D);
                treeContainer.innerHTML = this.renderMeshTree(meshStructure, node);
                
                // 绑定选中事件
                this.bindMeshSelectionEvents(meshPanel, node);
                
                // 保存当前节点
                this._previousNode = node;
            } else {
                // 同一个节点，但检查是否需要从搜索模式切换回普通模式
                // 如果当前显示的是搜索结果，需要重新渲染为普通mesh树
                const isShowingSearchResults = treeContainer.querySelector('.mesh-search-results');
                if (isShowingSearchResults) {
                    this.removeOutlineEffect();
                    
                    // 解析并渲染mesh结构
                    const meshStructure = this.parseMeshStructure(node.object3D);
                    treeContainer.innerHTML = this.renderMeshTree(meshStructure, node);
                    
                    // 绑定选中事件
                    this.bindMeshSelectionEvents(meshPanel, node);
                } else {
                }
            }
        }
        
        // 4. ⚠️ 不在这里保存mesh的transform
        // 保存操作已移到 bindMeshSelectionEvents 和 bindMeshSearchSelectionEvents 中
        // 每次渲染mesh列表后，会自动保存当前显示的所有mesh的transform作为重置基准点
        
        // 5. 重置mesh展开层级计数器
        if (window.meshExpandLevel !== undefined) {
            window.meshExpandLevel = 0;
        }
    }
    
    /**
     * 显示Mesh结构树窗口（兼容旧接口，调用enterMeshEditMode）
     * @param {TreeNode} node - 节点
     */
    showMeshStructure(node) {
        this.enterMeshEditMode(node);
    }
    
    /**
     * 更新mesh结构面板（当选中节点变化时）
     * @param {TreeNode} node - 当前选中的节点
     */
    updateMeshStructurePanel(node) {
        const meshPanel = document.getElementById('mesh-structure-panel');
        if (!meshPanel || !meshPanel.classList.contains('active')) {
            return; // 面板未打开，不更新
        }
        
        // 如果节点没有模型组件，退出mesh编辑模式
        if (!this.nodeHasModel(node)) {
            this.exitMeshEditMode();
            return;
        }
        
        // 调用统一的刷新方法
        this.refreshMeshEditMode(node);
    }
    
    /**
     * 解析Mesh结构（显示当前节点内部的mesh结构，不包含场景树子节点）
     * @param {THREE.Object3D} object3D - 3D对象
     * @param {number} level - 层级（用于缩进）
     * @returns {Object} mesh结构数据
     */
    parseMeshStructure(object3D, level = 0) {
        const structure = {
            name: object3D.name || '(unnamed)',
            type: object3D.type,
            isMesh: object3D.isMesh || false,
            uuid: object3D.uuid,
            level: level,
            children: []
        };
        
        // 如果是Mesh，添加几何信息
        if (object3D.isMesh) {
            const geometry = object3D.geometry;
            structure.geometryInfo = {
                vertices: geometry.attributes.position?.count || 0,
                faces: geometry.index ? geometry.index.count / 3 : 0
            };
            
            // 材质信息
            const materials = Array.isArray(object3D.material) ? object3D.material : [object3D.material];
            structure.materialInfo = materials.map(mat => ({
                type: mat.type,
                name: mat.name || '(unnamed)'
            }));
        }
        
        // 递归处理子对象，但要排除那些也是场景树节点的对象
        if (object3D.children && object3D.children.length > 0) {
            object3D.children.forEach(child => {
                // ✅ 过滤掉场景树的子节点（通过检查uuid是否在nodesMap中）
                // 只保留模型内部的mesh结构
                if (this.treeManager.nodesMap.has(child.uuid)) {
                    return; // 这是场景树的子节点，不显示在mesh结构中
                }
                
                // 递归解析子对象的mesh结构
                const childStructure = this.parseMeshStructure(child, level + 1);
                structure.children.push(childStructure);
            });
        }
        
        return structure;
    }
    
    /**
     * 统一的显示mesh面板方法（集中处理补位逻辑）
     * 所有需要显示mesh面板的地方都应该调用这个方法
     */
    showMeshPanel() {
        let meshPanel = document.getElementById('mesh-structure-panel');
        if (!meshPanel) {
            meshPanel = this.createMeshPanel();
            document.body.appendChild(meshPanel);
        }
        
        // ⚠️ 确保事件监听器已绑定（使用命名函数避免重复绑定）
        // 移除标志检查，每次都调用 setupMeshSearchListeners（内部会处理重复绑定）
        this.setupMeshSearchListeners(meshPanel);
        
        // 添加 active 类
        meshPanel.classList.add('active');
        
        // ⭐ 统一的补位逻辑判断：检查左侧面板状态，避免界面重叠
        const leftPanelWrapper = document.getElementById('left-panel-wrapper');
        if (leftPanelWrapper) {
            const isPanelHidden = leftPanelWrapper.classList.contains('hidden');
            if (isPanelHidden) {
                meshPanel.classList.add('left-panel-hidden');
            } else {
                meshPanel.classList.remove('left-panel-hidden');
            }
        }
        
        return meshPanel;
    }
    
    /**
     * 创建Mesh面板
     * @returns {HTMLElement} mesh面板元素
     */
    createMeshPanel() {
        const panel = document.createElement('div');
        panel.id = 'mesh-structure-panel';
        panel.className = 'side-panel left-panel mesh-panel';
        
        panel.innerHTML = `
            <!-- 面板标题 -->
            <div class="panel-header">
                <div class="panel-title">
                    <span class="panel-icon">🔷</span>
                    <span id="mesh-panel-title">Mesh模式</span>
                </div>
                <div class="panel-header-actions">
                    <button class="panel-close-btn" title="关闭">✕</button>
                </div>
            </div>
            
            <!-- Mesh搜索框 -->
            <div class="mesh-search-container">
                <input type="text" id="mesh-search-input" class="mesh-search-input" placeholder="搜索全部Mesh..." />
                <button class="mesh-search-clear" id="mesh-search-clear" title="清除搜索" style="display: none;">✕</button>
            </div>
            
            <!-- 工具栏 -->
            <div class="mesh-toolbar" style="padding: 8px; border-bottom: 1px solid #333; display: flex; gap: 8px;">
                <button id="resetModelHierarchyBtn" class="mesh-toolbar-btn" title="重置模型所有层级的Transform到原始状态" style="flex: 1; padding: 6px 12px; background: #2a2a2a; color: #ddd; border: 1px solid #444; border-radius: 4px; cursor: pointer; font-size: 12px;">
                    🔄 重置模型层级
                </button>
            </div>
            
            <!-- 面板内容 -->
            <div class="panel-body">
                <div class="mesh-tree-container"></div>
            </div>
        `;
        
        // 绑定关闭按钮事件
        const closeBtn = panel.querySelector('.panel-close-btn');
        closeBtn.addEventListener('click', () => this.exitMeshEditMode());
        
        // 绑定重置模型层级按钮事件
        const resetModelHierarchyBtn = panel.querySelector('#resetModelHierarchyBtn');
        if (resetModelHierarchyBtn) {
            resetModelHierarchyBtn.addEventListener('click', () => {
                console.log('🔄 [重置模型层级] 用户点击重置按钮');
                
                // 收集需要重置的节点
                const nodesToReset = new Set();
                
                // 1. 如果有当前mesh编辑节点，加入列表
                if (this._currentMeshEditNode) {
                    nodesToReset.add(this._currentMeshEditNode);
                }
                
                // 2. 添加所有被编辑过的节点
                if (this._editedNodes && this._editedNodes.size > 0) {
                    this._editedNodes.forEach(node => nodesToReset.add(node));
                }
                
                // 3. 如果还是没有，尝试使用当前选中的节点
                if (nodesToReset.size === 0 && this.treeManager.selectedNode) {
                    nodesToReset.add(this.treeManager.selectedNode);
                }
                
                // 检查是否有节点需要重置
                if (nodesToReset.size === 0) {
                    console.warn('⚠️ [重置模型层级] 没有需要重置的节点');
                    if (window.showMessage) {
                        window.showMessage('没有需要重置的节点', 'warning');
                    }
                    return;
                }
                
                // 重置所有节点
                let totalRestored = 0;
                let totalNotFound = 0;
                let successCount = 0;
                const resetNodes = [];
                
                nodesToReset.forEach(node => {
                    if (!node.object3D) {
                        console.warn(`⚠️ 节点 "${node.name}" 没有object3D，跳过`);
                        return;
                    }
                    
                    if (!node.hasModelHierarchyTransforms()) {
                        console.warn(`⚠️ 节点 "${node.name}" 没有保存的原始transform数据，跳过`);
                        return;
                    }
                    
                    // 执行重置
                    const result = node.resetModelHierarchyTransforms();
                    totalRestored += result.restored;
                    totalNotFound += result.notFound;
                    successCount++;
                    resetNodes.push(node.name);
                });
                
                // 清空已编辑节点列表
                this._editedNodes.clear();
                
                // 显示提示
                if (window.showMessage) {
                    if (successCount === 0) {
                        window.showMessage('没有可重置的节点（缺少原始Transform数据）', 'warning');
                    } else if (totalNotFound > 0) {
                        window.showMessage(
                            `已重置 ${successCount} 个节点，共 ${totalRestored} 个对象\n节点: ${resetNodes.join(', ')}\n${totalNotFound} 个对象未找到原始数据`, 
                            'warning'
                        );
                    } else {
                        window.showMessage(
                            `已成功重置 ${successCount} 个节点，共 ${totalRestored} 个对象\n节点: ${resetNodes.join(', ')}`, 
                            'success'
                        );
                    }
                }
            });
        }
        
        // ⚠️ 事件监听器在 showMeshPanel() 中统一设置，避免重复绑定
        
        return panel;
    }
    
    /**
     * 设置Mesh搜索事件监听
     * @param {HTMLElement} panel - mesh面板元素
     */
    setupMeshSearchListeners(panel) {
        const searchInput = panel.querySelector('#mesh-search-input');
        const clearBtn = panel.querySelector('#mesh-search-clear');
        
        if (!searchInput || !clearBtn) {
            console.error('❌ [Mesh搜索] 找不到搜索输入框或清除按钮');
            console.log('   searchInput:', searchInput);
            console.log('   clearBtn:', clearBtn);
            return;
        }
        
        console.log('✅ [Mesh搜索] 绑定事件监听器');
        
        // 使用命名函数，避免重复绑定
        // 先移除旧的监听器（如果存在）
        if (this._meshSearchInputHandler) {
            searchInput.removeEventListener('input', this._meshSearchInputHandler);
        }
        if (this._meshSearchClearHandler) {
            clearBtn.removeEventListener('click', this._meshSearchClearHandler);
        }
        if (this._meshSearchKeydownHandler) {
            searchInput.removeEventListener('keydown', this._meshSearchKeydownHandler);
        }
        
        // 实时搜索
        this._meshSearchInputHandler = (e) => {
            console.log('🔍 [Mesh搜索] 搜索输入:', e.target.value);
            this.handleMeshSearch(e.target.value);
        };
        searchInput.addEventListener('input', this._meshSearchInputHandler);
        
        // 清除搜索
        this._meshSearchClearHandler = () => {
            console.log('🗑️ [清除搜索] 清除mesh搜索');
            
            // 1. 先重置所有被修改的Mesh（恢复到原始状态，但不清空缓存）
            // ⚠️ 注意：这里会恢复所有在搜索模式下移动过的mesh
            if (this._meshOriginalTransforms.size > 0) {
                console.log('🔄 [清除搜索] 恢复所有mesh变换');
                this.restoreAllMeshOriginalTransforms(null, false);
            }
            
            // 2. 清除所有选中的Mesh
            this.selectedMeshes = [];
            
            // 3. 清除搜索关键词和搜索结果
            searchInput.value = '';
            this.meshSearchKeyword = '';
            this.meshSearchMatches = [];
            
            // 4. 更新清除按钮显示
            clearBtn.style.display = 'none';
            
            // 5. 移除轮廓和TransformControls
            this.removeOutlineEffect();
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.detach();
            }
            
            // 6. 重新渲染当前节点的Mesh树（回到节点的Mesh模式）
            if (this._currentMeshEditNode) {
                const meshPanel = document.getElementById('mesh-structure-panel');
                if (meshPanel) {
                    const treeContainer = meshPanel.querySelector('.mesh-tree-container');
                    if (treeContainer) {
                        // 渲染当前节点的mesh结构
                        const meshStructure = this.parseMeshStructure(this._currentMeshEditNode.object3D);
                        treeContainer.innerHTML = this.renderMeshTree(meshStructure, this._currentMeshEditNode);
                        
                        // 绑定选中事件
                        this.bindMeshSelectionEvents(meshPanel, this._currentMeshEditNode);
                    }
                }
            }
            
            console.log('✅ [清除搜索] 搜索已清除');
            searchInput.focus();
        };
        clearBtn.addEventListener('click', this._meshSearchClearHandler);
        
        // 回车键聚焦到第一个匹配项
        this._meshSearchKeydownHandler = (e) => {
            if (e.key === 'Enter' && this.meshSearchMatches.length > 0) {
                // 选中第一个匹配的mesh
                const firstMatch = this.meshSearchMatches[0];
                this.selectMeshInSearchMode(firstMatch);
            }
        };
        searchInput.addEventListener('keydown', this._meshSearchKeydownHandler);
    }
    
    /**
     * 清除Mesh搜索（重置并清空缓存）
     * ⚠️ 符合mesh模式文档要求：重置mesh变换、清空缓存、清空搜索状态
     */
    clearMeshSearch() {
        // 1. 重置所有mesh的transform并清空缓存
        if (this._meshOriginalTransforms.size > 0) {
            this.restoreAllMeshOriginalTransforms(null, true); // 重置并清空
        }
        
        // 2. 清空搜索状态
        this.meshSearchKeyword = '';
        this.meshSearchMatches = [];
        this.selectedMeshes = [];
        
        // 3. 清空mesh-node缓存
        if (this.meshNodeCache.size > 0) {
            this.meshNodeCache.clear();
        }
        
        // 4. 更新UI
        const searchInput = document.getElementById('mesh-search-input');
        if (searchInput) {
            searchInput.value = '';
        }
        const clearBtn = document.getElementById('mesh-search-clear');
        if (clearBtn) {
            clearBtn.style.display = 'none';
        }
        
        // 5. 移除轮廓效果
        this.removeOutlineEffect();
        
        // 6. 分离TransformControls
        const currentScene = window.manager?.getCurrentScene();
        if (currentScene && currentScene.transformControlsManager) {
            currentScene.transformControlsManager.detach();
        }
    }
    
    /**
     * 处理Mesh搜索
     * @param {string} keyword - 搜索关键词
     */
    handleMeshSearch(keyword) {
        const newKeyword = keyword.trim().toLowerCase();
        
        // 🔧 符合mesh模式文档要求：搜索前重置并清空缓存
        // 如果是新的搜索（从无到有，或从有到无，或关键词变化）
        const isNewSearch = newKeyword !== this.meshSearchKeyword;
        
        if (isNewSearch) {
            console.log('🔄 [Mesh搜索] 搜索状态改变，重置所有被编辑过的节点');
            
            // 1. 重置mesh编辑模式下的mesh变换（如果有）
            if (this._meshOriginalTransforms.size > 0) {
                console.log('   🔄 重置mesh编辑模式的mesh变换');
                this.restoreAllMeshOriginalTransforms(null, true); // 重置并清空
            }
            
            // 2. 重置所有被编辑过的节点的模型层级transform
            if (this._editedNodes && this._editedNodes.size > 0) {
                console.log(`   🔄 重置 ${this._editedNodes.size} 个被编辑过的节点的模型层级`);
                this._editedNodes.forEach(node => {
                    if (node.hasModelHierarchyTransforms()) {
                        node.resetModelHierarchyTransforms();
                        console.log(`      ✅ 重置节点: "${node.name}"`);
                    }
                });
                // 清空已编辑节点列表
                this._editedNodes.clear();
            }
            
            // 3. 清空mesh-node缓存（准备建立新的缓存）
            if (this.meshNodeCache.size > 0) {
                this.meshNodeCache.clear();
            }
        }
        
        this.meshSearchKeyword = newKeyword;
        this.meshSearchMatches = [];
        
        // 更新清除按钮显示
        const clearBtn = document.getElementById('mesh-search-clear');
        if (clearBtn) {
            clearBtn.style.display = this.meshSearchKeyword ? 'flex' : 'none';
        }
        
        // 如果有搜索关键词，遍历整个场景树查找所有匹配的Mesh
        if (this.meshSearchKeyword) {
            // 遍历所有场景树节点
            this.treeManager.traverse(node => {
                if (node.id === 'root') return;
                
                // 如果节点有object3D，遍历其所有子对象查找mesh
                if (node.object3D) {
                    this.collectMeshesFromObject(node, node.object3D, []);
                }
            });
        }
        
        // 重新渲染mesh树
        if (this._currentMeshEditNode) {
            this.refreshMeshEditMode(this._currentMeshEditNode);
        } else {
            // 🔧 修复：即使没有当前编辑节点，也要显示搜索结果
            // 这样用户在直接使用搜索框时就能看到结果
            const meshPanel = document.getElementById('mesh-structure-panel');
            if (meshPanel) {
                const treeContainer = meshPanel.querySelector('.mesh-tree-container');
                if (treeContainer) {
                    if (this.meshSearchKeyword) {
                        // 显示搜索结果
                        this.removeOutlineEffect();
                        treeContainer.innerHTML = this.renderMeshSearchResults();
                        this.bindMeshSearchSelectionEvents(meshPanel);
                    } else {
                        // 清空显示
                        treeContainer.innerHTML = '<div style="padding: 20px; text-align: center; color: #888;">请先选择一个节点进入Mesh模式</div>';
                    }
                }
            }
        }
    }
    
    /**
     * 从对象中收集所有匹配的Mesh
     * @param {TreeNode} node - 场景树节点
     * @param {THREE.Object3D} object3D - 3D对象
     * @param {string[]} path - 路径数组
     */
    collectMeshesFromObject(node, object3D, path) {
        // 检查当前对象是否是Mesh且名称匹配
        if (object3D.isMesh) {
            const meshName = object3D.name || '(unnamed)';
            if (meshName.toLowerCase().includes(this.meshSearchKeyword)) {
                // 添加到搜索结果（不去重，因为不同节点的同名mesh是不同的实例）
                this.meshSearchMatches.push({
                    node: node, // 所属的场景树节点
                    mesh: object3D, // mesh对象
                    path: [...path, meshName], // 完整路径
                    nodeName: node.name // 节点名称
                });
                
                // 🔍 调试：记录mesh信息
                console.log(`  📦 收集Mesh: "${meshName}" (UUID: ${object3D.uuid.substring(0, 8)}, 节点: "${node.name}")`);
            }
        }
        
        // 递归处理子对象（排除场景树子节点）
        if (object3D.children && object3D.children.length > 0) {
            const currentPath = object3D.isMesh ? [...path, object3D.name || '(unnamed)'] : path;
            
            object3D.children.forEach(child => {
                // 排除场景树的子节点
                if (this.treeManager.nodesMap.has(child.uuid)) {
                    return;
                }
                
                this.collectMeshesFromObject(node, child, currentPath);
            });
        }
    }
    
    /**
     * 在搜索模式下选中Mesh
     * @param {Object} matchItem - 搜索匹配项 {node, mesh, path, nodeName}
     */
    selectMeshInSearchMode(matchItem) {
        // 🔧 进入mesh编辑模式，取消选择场景树节点（清空缓存）
        // 保存当前编辑节点的引用
        this._currentMeshEditNode = matchItem.node;
        if (this.treeManager.selectedNode) {
            this.treeManager.deselectNode();
        }
        
        // 添加轮廓效果
        this.removeOutlineEffect();
        this.addOutlineEffect(matchItem.mesh);
        
        // 附加TransformControls
        const currentScene = window.manager?.getCurrentScene();
        if (currentScene && currentScene.transformControlsManager) {
            currentScene.transformControlsManager.attach(matchItem.mesh);
        }
        
        // 设置F键聚焦目标
        this._focusTarget = matchItem.mesh;
        this._focusTargetType = 'mesh';
    }
    
    /**
     * 渲染Mesh搜索结果
     * @returns {string} HTML字符串
     */
    renderMeshSearchResults() {
        if (this.meshSearchMatches.length === 0) {
            return `
                <div class="mesh-search-no-result">
                    <div style="padding: 40px 20px; text-align: center; color: #888;">
                        <div style="font-size: 48px; margin-bottom: 10px;">🔍</div>
                        <div>未找到匹配的Mesh</div>
                    </div>
                </div>
            `;
        }
        
        // 并列显示所有搜索结果
        let html = '<div class="mesh-search-results">';
        
        // 添加全选按钮头部
        html += `
            <div class="mesh-search-header">
                <div class="mesh-search-count">找到 ${this.meshSearchMatches.length} 个Mesh</div>
                <button class="mesh-select-all-btn" id="mesh-select-all-btn" title="全选/取消全选所有搜索结果">
                    <span class="select-all-icon">☑</span>
                    <span class="select-all-text">全选</span>
                </button>
            </div>
        `;
        
        this.meshSearchMatches.forEach((matchItem, index) => {
            const { node, mesh, path, nodeName } = matchItem;
            
            // 获取mesh的几何信息
            let geometryInfo = '';
            if (mesh.geometry) {
                const vertices = mesh.geometry.attributes.position?.count || 0;
                const faces = mesh.geometry.index ? mesh.geometry.index.count / 3 : 0;
                geometryInfo = `顶点: ${vertices} | 面: ${faces}`;
            }
            
            // 获取材质信息
            const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
            const materialNames = materials.map(mat => mat.name || mat.type).join(', ');
            
            // 完整路径（节点名 > 路径）
            const fullPath = `${nodeName} > ${path.join(' > ')}`;
            
            // 渲染搜索结果项（简洁版，无图标和聚焦按钮）
            html += `
                <div class="mesh-search-result-item" data-index="${index}" data-uuid="${mesh.uuid}">
                    <div class="mesh-result-content">
                        <div class="mesh-result-info">
                            <div class="mesh-result-name">${mesh.name || '(unnamed)'}</div>
                            <div class="mesh-result-path">${fullPath}</div>
                            <div class="mesh-result-details">
                                <span class="mesh-result-geometry">${geometryInfo}</span>
                                ${materialNames ? `<span class="mesh-result-material">材质: ${materialNames}</span>` : ''}
                            </div>
                        </div>
                    </div>
                </div>
            `;
        });
        
        html += '</div>';
        
        return html;
    }
    
    /**
     * 绑定Mesh搜索结果的选择事件
     * @param {HTMLElement} meshPanel - mesh面板元素
     */
    bindMeshSearchSelectionEvents(meshPanel) {
        const resultItems = meshPanel.querySelectorAll('.mesh-search-result-item');
        const selectAllBtn = meshPanel.querySelector('#mesh-select-all-btn');
        
        // ⭐ 建立搜索结果的mesh-node缓存
        let cachedCount = 0;
        this.meshSearchMatches.forEach(matchItem => {
            if (matchItem.mesh && matchItem.node) {
                this.meshNodeCache.set(matchItem.mesh.uuid, matchItem.node);
                cachedCount++;
            }
        });
        
        // ⚠️ 保存所有搜索结果mesh的原始transform（作为重置基准点）
        if (this.meshSearchMatches.length > 0) {
            this.saveCurrentMeshTransforms(this.meshSearchMatches);
        }
        // 绑定全选按钮事件
        if (selectAllBtn) {
            selectAllBtn.addEventListener('click', () => {
                this.toggleSelectAllMeshes(resultItems);
            });
        }
        
        resultItems.forEach(item => {
            const index = parseInt(item.dataset.index);
            const matchItem = this.meshSearchMatches[index];
            
            // 点击事件：选中mesh
            item.addEventListener('click', (e) => {
                // 检查是否按住Ctrl键（多选）
                const isCtrlPressed = e.ctrlKey || e.metaKey;
                
                // 每次单击后更新全选按钮状态
                setTimeout(() => this.updateSelectAllButtonState(), 0);
                
                // 取消场景树中当前选中的节点
                if (this.treeManager.selectedNode) {
                    this.treeManager.deselectNode();
                }
                
                if (isCtrlPressed) {
                    // 多选模式
                    this.toggleMeshSelection(item, matchItem);
                } else {
                    // 单选模式
                    // 清除其他选中状态
                    resultItems.forEach(ri => ri.classList.remove('selected'));
                    this.selectedMeshes = [];
                    
                    // 选中当前mesh
                    item.classList.add('selected');
                    this.selectedMeshes.push(matchItem);
                    
                    // 显示轮廓和TransformControls
                    this.selectMeshInSearchMode(matchItem);
                }
            });
        });
    }
    
    /**
     * 切换Mesh选择状态（Ctrl+点击多选）
     * @param {HTMLElement} item - 结果项元素
     * @param {Object} matchItem - 匹配项数据
     */
    toggleMeshSelection(item, matchItem) {
        const isSelected = item.classList.contains('selected');
        
        if (isSelected) {
            // 取消选中
            item.classList.remove('selected');
            const index = this.selectedMeshes.findIndex(m => m.mesh.uuid === matchItem.mesh.uuid);
            if (index > -1) {
                this.selectedMeshes.splice(index, 1);
            }
        } else {
            // 添加到选中列表
            item.classList.add('selected');
            this.selectedMeshes.push(matchItem);
        }
        
        // 更新轮廓显示（显示第一个选中的mesh）
        if (this.selectedMeshes.length > 0) {
            this.removeOutlineEffect();
            this.addOutlineEffect(this.selectedMeshes[0].mesh);
            
            // 附加TransformControls到第一个选中的mesh
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.attach(this.selectedMeshes[0].mesh);
            }
        } else {
            // 没有选中的mesh，移除轮廓和TransformControls
            this.removeOutlineEffect();
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.detach();
            }
        }
        
        // 更新全选按钮状态
        this.updateSelectAllButtonState();
    }
    
    /**
     * 切换全选/取消全选所有搜索结果
     * @param {NodeList} resultItems - 所有搜索结果项元素
     */
    toggleSelectAllMeshes(resultItems) {
        const allSelected = this.selectedMeshes.length === this.meshSearchMatches.length;
        
        if (allSelected) {
            // 全部已选中，执行取消全选
            resultItems.forEach(item => {
                item.classList.remove('selected');
            });
            this.selectedMeshes = [];
            
            // 移除轮廓和TransformControls
            this.removeOutlineEffect();
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.detach();
            }
        } else {
            // 未全选或部分选中，执行全选
            // 取消场景树中当前选中的节点
            if (this.treeManager.selectedNode) {
                this.treeManager.deselectNode();
            }
            
            // 清空原有选择
            this.selectedMeshes = [];
            
            // 选中所有
            resultItems.forEach((item, index) => {
                item.classList.add('selected');
                const matchItem = this.meshSearchMatches[index];
                
                // 添加到选中列表
                this.selectedMeshes.push(matchItem);
            });
            
            // 显示第一个mesh的轮廓和TransformControls
            if (this.selectedMeshes.length > 0) {
                this.removeOutlineEffect();
                this.addOutlineEffect(this.selectedMeshes[0].mesh);
                
                const currentScene = window.manager?.getCurrentScene();
                if (currentScene && currentScene.transformControlsManager) {
                    currentScene.transformControlsManager.attach(this.selectedMeshes[0].mesh);
                }
            }
        }
        
        // 更新按钮状态
        this.updateSelectAllButtonState();
    }
    
    /**
     * 更新全选按钮的状态（文字和图标）
     */
    updateSelectAllButtonState() {
        const selectAllBtn = document.getElementById('mesh-select-all-btn');
        if (!selectAllBtn) return;
        
        const allSelected = this.selectedMeshes.length === this.meshSearchMatches.length;
        const iconSpan = selectAllBtn.querySelector('.select-all-icon');
        const textSpan = selectAllBtn.querySelector('.select-all-text');
        
        if (allSelected && this.meshSearchMatches.length > 0) {
            // 全选状态
            if (iconSpan) iconSpan.textContent = '☑';
            if (textSpan) textSpan.textContent = '取消全选';
            selectAllBtn.classList.add('all-selected');
        } else {
            // 未全选状态
            if (iconSpan) iconSpan.textContent = '☐';
            if (textSpan) textSpan.textContent = '全选';
            selectAllBtn.classList.remove('all-selected');
        }
    }
    
    /**
     * 退出Mesh编辑模式
     * 场景：关闭mesh窗口、点击无模型节点、移除模型组件
     */
    exitMeshEditMode() {
        const meshPanel = document.getElementById('mesh-structure-panel');
        if (!meshPanel || !meshPanel.classList.contains('active')) {
            return; // 没有进入mesh模式，无需退出
        }
        
        // 1. 先清理所有可能影响mesh状态的UI控件
        // 1.1 隐藏坐标轴（TransformControls），确保没有正在进行的变换操作
        const currentScene = window.manager?.getCurrentScene();
        if (currentScene && currentScene.transformControlsManager) {
            currentScene.transformControlsManager.detach();
        }
        
        // 1.2 隐藏边缘轮廓线
        this.removeOutlineEffect();
        
        // 1.3 清理mesh选中状态
        meshPanel.querySelectorAll('.mesh-tree-node.selected').forEach(n => {
            n.classList.remove('selected');
        });
        this._currentSelectedMesh = null; // 清空当前选中的mesh引用
        
        // 2. 重置当前节点的所有mesh的位置旋转缩放（恢复到进入mesh模式时的状态）
        if (this._currentMeshEditNode) {
            this.restoreAllMeshOriginalTransforms(null, true); // 重置并清空状态
        } else {
            console.warn('⚠️ 没有_currentMeshEditNode，无法恢复mesh变换');
        }
        
        // 3. 隐藏网格线
        if (this._wireframeEnabled && this._previousNode) {
            this.disableWireframe(this._previousNode);
            const wireframeBtn = document.getElementById('toggleWireframeBtn');
            if (wireframeBtn) {
                wireframeBtn.classList.remove('active');
            }
        }
        
        // 4. 清除Mesh-Node缓存
        if (this.meshNodeCache.size > 0) {
            this.meshNodeCache.clear();
        }
        
        // 5. 清除Mesh搜索状态
        this.meshSearchKeyword = '';
        this.meshSearchMatches = [];
        this.selectedMeshes = [];
        const meshSearchInput = document.getElementById('mesh-search-input');
        if (meshSearchInput) {
            meshSearchInput.value = '';
        }
        
        // 6. 清空mesh面板内容
        const treeContainer = meshPanel.querySelector('.mesh-tree-container');
        if (treeContainer) {
            treeContainer.innerHTML = '';
        }
        
        // 6.5. 重置mesh展开层级计数器
        if (window.meshExpandLevel !== undefined) {
            window.meshExpandLevel = 0;
        }
        
        // 7. 关闭mesh面板
        meshPanel.classList.remove('active');
        
        // 8. 清除属性面板
        const inspector = document.getElementById('inspector-panel');
        if (inspector) {
            inspector.style.display = 'none';
        }
        
        // 9. 清空mesh模式相关的状态变量
        this._previousNode = null;
        // ⚠️ 确保清空mesh模式节点缓存（_currentMeshEditNode 在 restoreAllMeshOriginalTransforms(null, true) 中已清空）
        if (this._currentMeshEditNode) {
            this._currentMeshEditNode = null;
        }
        
        // 10. 清除F键聚焦目标
        this._focusTarget = null;
        this._focusTargetType = null;
    }
    
    /**
     * 从缓存中获取mesh所属的节点
     * ⭐ 高性能查找：O(1) 时间复杂度
     * @param {THREE.Mesh} mesh - Mesh对象
     * @returns {TreeNode|null} 节点对象
     */
    getNodeByMesh(mesh) {
        if (!mesh || !mesh.uuid) {
            return null;
        }
        
        const cachedNode = this.meshNodeCache.get(mesh.uuid);
        if (cachedNode) {
            return cachedNode;
        }
        
        console.warn('⚠️ Mesh-Node缓存未命中，可能需要先显示mesh面板或搜索mesh');
        return null;
    }
    
    /**
     * 渲染Mesh树
     * @param {Object} structure - mesh结构数据
     * @param {TreeNode} node - 场景树节点（可选，用于保存到按钮）
     * @returns {string} HTML字符串
     */
    renderMeshTree(structure, node = null) {
        // 基础缩进2px，每层增加12px
        const baseIndent = 2;
        const indent = baseIndent + (structure.level * 12);
        const isMesh = structure.isMesh;
        const hasChildren = structure.children && structure.children.length > 0;
        const toggleIcon = hasChildren ? '▼' : ''; // 默认展开，显示向下箭头
        
        // 简化结构，去掉嵌套的背景层
        let html = `
            <div class="mesh-tree-item" data-uuid="${structure.uuid}">
                <div class="mesh-tree-node mesh-selectable" data-uuid="${structure.uuid}" data-is-mesh="${isMesh}" style="padding-left: ${indent}px;">
                    ${hasChildren ? `<span class="mesh-node-toggle expanded" onclick="event.stopPropagation(); toggleMeshNode(this)">${toggleIcon}</span>` : '<span class="mesh-node-toggle empty"></span>'}
        `;
        
        // 如果是Mesh，M标记在名字前面
        if (isMesh) {
            html += `<span class="mesh-node-type mesh-type-m">M</span>`;
        }
        
        html += `<span class="mesh-node-name">${structure.name}</span>`;
        
        // 如果不是Mesh，显示完整类型在名字后面
        if (!isMesh) {
            html += `<span class="mesh-node-type">${structure.type}</span>`;
        }
        
        // 如果是Mesh，显示简化的顶点数
        if (isMesh && structure.geometryInfo) {
            const vertexCount = this.formatVertexCount(structure.geometryInfo.vertices);
            html += `<span class="mesh-node-info">${vertexCount}</span>`;
        }
        
        // 如果是Mesh，添加显隐按钮和材质按钮
        if (isMesh) {
            const nodeIdAttr = node ? `data-node-id="${node.id}"` : '';
            html += `
                    <button class="mesh-visibility-btn" data-uuid="${structure.uuid}" ${nodeIdAttr} onclick="event.stopPropagation(); toggleMeshVisibility(this)" title="显示/隐藏">
                        👁
                    </button>
                    <button class="mesh-material-btn" data-uuid="${structure.uuid}" ${nodeIdAttr} onclick="event.stopPropagation(); window.sceneTreeUI.showMeshMaterialDialog(this)" title="编辑材质">
                        🎨
                    </button>
            `;
        }
        
        html += `</div>`;
        
        // 递归渲染子节点 - 默认展开
        if (hasChildren) {
            html += `<div class="mesh-node-children expanded">`;
            structure.children.forEach(child => {
                html += this.renderMeshTree(child, node);  // 传递节点参数
            });
            html += `</div>`;
        }
        
        html += `</div>`;
        
        return html;
    }
    
    /**
     * 格式化顶点数显示
     * @param {number} count - 顶点数
     * @returns {string} 格式化后的字符串
     */
    formatVertexCount(count) {
        if (count >= 100000000) { // 1亿以上
            return Math.floor(count / 100000000) + '亿';
        } else if (count >= 10000) { // 1万以上
            return Math.floor(count / 10000) + 'W';
        } else if (count >= 1000) { // 1千以上
            return Math.floor(count / 1000) + 'K';
        } else {
            return count.toString();
        }
    }
    
    /**
     * 绑定对象选中事件（支持所有3D对象，不仅限于Mesh）
     * @param {HTMLElement} panel - mesh面板
     * @param {TreeNode} node - 当前场景树节点
     */
    bindMeshSelectionEvents(panel, node) {
        const meshNodes = panel.querySelectorAll('.mesh-selectable');
        
        // ⭐ 建立mesh-node缓存：遍历所有mesh，记录它们与node的关系
        // 同时收集所有mesh对象，用于保存原始transform
        const meshList = [];
        meshNodes.forEach(meshNode => {
            const objectUuid = meshNode.dataset.uuid;
            const object3D = node.object3D.getObjectByProperty('uuid', objectUuid);
            if (object3D && object3D.isMesh) {
                this.meshNodeCache.set(object3D.uuid, node);
                meshList.push({ mesh: object3D, node: node });
            }
        });
        
        // ⚠️ 保存当前显示的所有mesh的原始transform（作为重置基准点）
        if (meshList.length > 0) {
            this.saveCurrentMeshTransforms(meshList);
        }
        meshNodes.forEach(meshNode => {
            meshNode.onclick = (e) => {
                e.stopPropagation();
                
                // 移除其他选中状态
                panel.querySelectorAll('.mesh-tree-node.selected').forEach(n => {
                    n.classList.remove('selected');
                });
                
                // 添加选中状态
                meshNode.classList.add('selected');
                
                // 获取对象的uuid和是否是mesh
                const objectUuid = meshNode.dataset.uuid;
                const isMesh = meshNode.dataset.isMesh === 'true';
                
                // 在3D场景中查找并选中该对象（可以是Mesh、Group等任何Object3D）
                const object3D = node.object3D.getObjectByProperty('uuid', objectUuid);
                if (object3D) {
                    // 🔧 进入mesh编辑模式，取消选择场景树节点（清空缓存）
                    // 但保存一个对当前编辑节点的引用，用于退出mesh模式时恢复选择
                    this._currentMeshEditNode = node;
                    if (this.treeManager.selectedNode) {
                        this.treeManager.deselectNode();
                    }
                    // 移除场景树节点的视觉高亮
                    this.container.querySelectorAll('.tree-node-content.selected').forEach(el => {
                        el.classList.remove('selected');
                    });
                    // 添加轮廓高亮效果（不论是Mesh还是其他Object3D）
                    this.addOutlineEffect(object3D);
                    
                    // 🔧 聚焦到选中的对象（不论是Mesh、Group还是其他Object3D）
                    this.focusOnMesh(object3D);
                    
                    // 如果有TransformControls，附加到该对象
                    // 注意：mesh编辑模式下不传递node，避免触发数据保存
                    const currentScene = window.manager?.getCurrentScene();
                    if (currentScene && currentScene.transformControlsManager) {
                        currentScene.transformControlsManager.attach(object3D, null);
                    }
                    
                    // 保存当前选中的mesh对象引用
                    this._currentSelectedMesh = object3D;
                    
                    // 设置F键聚焦目标为mesh
                    this._focusTarget = object3D;
                    this._focusTargetType = 'mesh';
                    // 关闭属性面板
                    if (window.rightToolbarManager) {
                        const transformPanel = window.rightToolbarManager.panels['transform'];
                        if (transformPanel && transformPanel.classList.contains('show')) {
                            window.rightToolbarManager.closePanel('transform');
                        }
                    }
                }
            };
        });
        
        // 点击面板空白区域，取消mesh选中
        const treeContainer = panel.querySelector('.mesh-tree-container');
        if (treeContainer) {
            treeContainer.onclick = (e) => {
                // 如果点击的是容器本身（不是mesh节点）
                if (e.target === treeContainer || e.target.classList.contains('mesh-empty')) {
                    const hasSelected = panel.querySelector('.mesh-tree-node.selected');
                    if (hasSelected) {
                        // 移除所有选中状态
                        panel.querySelectorAll('.mesh-tree-node.selected').forEach(n => {
                            n.classList.remove('selected');
                        });
                        this.deselectMesh(node);
                    }
                }
            };
        }
        
        // 同步显隐按钮状态
        this.syncMeshVisibilityButtons(panel, node);
    }
    
    /**
     * 取消选中Mesh，恢复节点轮廓
     * @param {TreeNode} node - 当前场景树节点
     */
    deselectMesh(node) {
        // 清空选中的mesh引用（但不恢复transform，只在退出mesh模式时才恢复）
        this._currentSelectedMesh = null;
        
        // 移除当前的轮廓效果
        this.removeOutlineEffect();
        
        // 🔧 使用 _currentMeshEditNode 来恢复节点选择
        // 如果当前正在编辑mesh的节点就是传入的节点，则恢复对该节点的选择
        if (this._currentMeshEditNode && this._currentMeshEditNode === node) {
            // 重新选中该节点（这会设置 selectedNode 缓存）
            this.treeManager.selectNode(node);
            
            // 恢复显示节点的轮廓线
            if (node.object3D) {
                this.addOutlineEffect(node.object3D);
            }
            
            // 恢复TransformControls到节点
            const currentScene = window.manager?.getCurrentScene();
            if (currentScene && currentScene.transformControlsManager) {
                currentScene.transformControlsManager.attach(node.object3D);
            }
            
            // 恢复F键聚焦目标为节点
            this._focusTarget = node.object3D;
            this._focusTargetType = 'node';
            
            // 清空mesh编辑节点引用
            this._currentMeshEditNode = null;
        } else {
            // 没有正在编辑的节点，清除聚焦目标
            this._focusTarget = null;
            this._focusTargetType = null;
            this._currentMeshEditNode = null;
        }
    }
    
    /**
     * 同步mesh显隐按钮的状态
     * @param {HTMLElement} panel - mesh面板
     * @param {TreeNode} node - 当前场景树节点
     */
    syncMeshVisibilityButtons(panel, node) {
        if (!node || !node.object3D) {
            console.warn('⚠️ 节点或 object3D 不存在，无法同步按钮状态');
            return;
        }
        
        const visibilityButtons = panel.querySelectorAll('.mesh-visibility-btn');
        
        visibilityButtons.forEach(button => {
            const meshUuid = button.dataset.uuid;
            if (!meshUuid) return;
            
            // 🔧 修复：使用双重查找策略
            let meshObject = node.object3D.getObjectByProperty('uuid', meshUuid);
            
            // 如果第一种方法失败，手动递归查找
            if (!meshObject) {
                node.object3D.traverse((obj) => {
                    if (obj.uuid === meshUuid && obj.isMesh) {
                        meshObject = obj;
                    }
                });
            }
            
            if (meshObject && meshObject.isMesh) {
                // 根据mesh的visible状态更新按钮
                if (meshObject.visible) {
                    button.classList.remove('hidden');
                    button.textContent = '👁';
                    button.title = '隐藏';
                } else {
                    button.classList.add('hidden');
                    button.textContent = '👁‍🗨';
                    button.title = '显示';
                }
            }
        });
    }
    
    /**
     * 为Mesh添加坐标轴辅助对象
     * @param {THREE.Mesh} mesh - 目标mesh
     */
    addMeshAxesHelper(mesh) {
        if (!mesh || !THREE) return;
        
        // 计算mesh的包围盒，根据大小设置坐标轴长度
        mesh.geometry.computeBoundingBox();
        const boundingBox = mesh.geometry.boundingBox;
        const size = boundingBox.getSize(new THREE.Vector3());
        const axesSize = Math.max(size.x, size.y, size.z) * 0.5;
        
        // 创建坐标轴辅助对象
        const axesHelper = new THREE.AxesHelper(axesSize);
        axesHelper.name = '__meshAxesHelper__';
        
        // 添加到mesh
        mesh.add(axesHelper);
        
        // 保存引用以便后续移除
        this._currentMeshAxesHelper = axesHelper;
        this._currentMeshWithAxes = mesh;
    }
    
    /**
     * 移除Mesh的坐标轴辅助对象
     */
    removeMeshAxesHelper() {
        if (this._currentMeshAxesHelper && this._currentMeshWithAxes) {
            this._currentMeshWithAxes.remove(this._currentMeshAxesHelper);
            this._currentMeshAxesHelper = null;
            this._currentMeshWithAxes = null;
        }
    }
    
    /**
     * 聚焦到Mesh对象（使用CameraController的focusOn方法）
     * @param {THREE.Mesh} mesh - 目标mesh
     */
    focusOnMesh(mesh) {
        if (!mesh || !THREE) {
            console.warn('⚠️ mesh或THREE未定义');
            return;
        }
        
        const manager = window._sceneManager;
        const currentScene = manager?.getCurrentScene();
        if (!currentScene || !currentScene.cameraController) {
            console.warn('⚠️ 无法聚焦：场景或相机控制器未初始化');
            return;
        }
        // 使用CameraController的focusOn方法聚焦到mesh的包围盒
        // selfOnly=false 表示包括子节点计算包围盒
        // distanceMultiplier=1.5 表示距离为默认的1.5倍，更远的观察距离
        currentScene.cameraController.focusOn(mesh, 600, false, 1.5);
    }
    
    /**
     * 动画移动相机到目标位置
     * @param {THREE.Camera} camera - 相机
     * @param {THREE.Vector3} targetPosition - 目标位置
     * @param {OrbitControls} controls - 轨道控制器
     */
    animateCameraToPosition(camera, targetPosition, controls) {
        const startPosition = camera.position.clone();
        const duration = 500; // 动画时长500ms
        const startTime = performance.now();
        
        const animate = (currentTime) => {
            const elapsed = currentTime - startTime;
            const progress = Math.min(elapsed / duration, 1);
            
            // 使用easeInOutCubic缓动函数
            const eased = progress < 0.5
                ? 4 * progress * progress * progress
                : 1 - Math.pow(-2 * progress + 2, 3) / 2;
            
            // 插值计算当前位置
            camera.position.lerpVectors(startPosition, targetPosition, eased);
            
            // 更新controls
            if (controls) {
                controls.update();
            }
            
            // 继续动画
            if (progress < 1) {
                requestAnimationFrame(animate);
            }
        };
        
        requestAnimationFrame(animate);
    }
    
    /**
     * 添加聚焦点标记
     * @param {THREE.Vector3} position - 聚焦点位置
     */
    addFocusMarker(position) {
        if (!THREE) return;
        
        const manager = window._sceneManager;
        const currentScene = manager?.getCurrentScene();
        if (!currentScene || !currentScene.scene) return;
        
        // 创建聚焦点标记（一个小球体）
        const geometry = new THREE.SphereGeometry(0.1, 16, 16);
        const material = new THREE.MeshBasicMaterial({
            color: 0xff6b00,
            transparent: true,
            opacity: 0.8,
            depthTest: false // 始终可见
        });
        const marker = new THREE.Mesh(geometry, material);
        marker.position.copy(position);
        marker.name = '__focusMarker__';
        
        // 添加外圈（环）
        const ringGeometry = new THREE.RingGeometry(0.15, 0.2, 32);
        const ringMaterial = new THREE.MeshBasicMaterial({
            color: 0xff6b00,
            transparent: true,
            opacity: 0.5,
            side: THREE.DoubleSide,
            depthTest: false
        });
        const ring = new THREE.Mesh(ringGeometry, ringMaterial);
        ring.lookAt(currentScene.camera.position);
        marker.add(ring);
        
        currentScene.scene.add(marker);
        
        // 保存引用
        this._focusMarker = marker;
        
        // 添加脉冲动画
        this.animateFocusMarker(marker, ring);
    }
    
    /**
     * 移除聚焦点标记
     */
    removeFocusMarker() {
        if (this._focusMarker) {
            const manager = window._sceneManager;
            const currentScene = manager?.getCurrentScene();
            if (currentScene && currentScene.scene) {
                currentScene.scene.remove(this._focusMarker);
            }
            
            // 停止动画
            if (this._focusMarkerAnimationId) {
                cancelAnimationFrame(this._focusMarkerAnimationId);
                this._focusMarkerAnimationId = null;
            }
            
            this._focusMarker = null;
        }
    }
    
    /**
     * 聚焦点标记动画
     * @param {THREE.Mesh} marker - 标记对象
     * @param {THREE.Mesh} ring - 环对象
     */
    animateFocusMarker(marker, ring) {
        const startTime = performance.now();
        
        const animate = (currentTime) => {
            const elapsed = currentTime - startTime;
            const t = (elapsed % 2000) / 2000; // 2秒循环
            
            // 脉冲缩放
            const scale = 1 + Math.sin(t * Math.PI * 2) * 0.2;
            marker.scale.set(scale, scale, scale);
            
            // 旋转
            ring.rotation.z = t * Math.PI * 2;
            
            // 继续动画
            this._focusMarkerAnimationId = requestAnimationFrame(animate);
        };
        
        this._focusMarkerAnimationId = requestAnimationFrame(animate);
    }
    
    /**
     * 启用网格线显示
     * @param {TreeNode} node - 场景树节点
     */
    enableWireframe(node) {
        if (!node || !node.object3D) {
            console.warn('⚠️ 节点没有3D对象');
            return;
        }
        
        // 保存原始材质状态
        this._wireframeOriginalStates = new Map();
        
        // 遍历所有mesh，启用wireframe
        node.object3D.traverse((obj) => {
            if (obj.isMesh && obj.material) {
                const materials = Array.isArray(obj.material) ? obj.material : [obj.material];
                
                materials.forEach((mat) => {
                    // 保存原始状态
                    if (!this._wireframeOriginalStates.has(mat.uuid)) {
                        this._wireframeOriginalStates.set(mat.uuid, {
                            wireframe: mat.wireframe,
                            material: mat
                        });
                    }
                    
                    // 启用wireframe
                    mat.wireframe = true;
                });
            }
        });
        
        this._wireframeEnabled = true;
    }
    
    /**
     * 禁用网格线显示
     * @param {TreeNode} node - 场景树节点
     */
    disableWireframe(node) {
        if (!this._wireframeOriginalStates || this._wireframeOriginalStates.size === 0) {
            this._wireframeEnabled = false;
            return;
        }
        
        // 恢复原始材质状态
        this._wireframeOriginalStates.forEach((state) => {
            if (state.material) {
                state.material.wireframe = state.wireframe;
            }
        });
        
        this._wireframeOriginalStates.clear();
        this._wireframeEnabled = false;
    }
    
    /**
     * 重置所有mesh的显隐状态
     * @param {TreeNode} node - 场景树节点
     */
    resetAllMeshVisibility(node) {
        if (!node || !node.object3D) {
            return;
        }
        
        let resetCount = 0;
        
        // 遍历所有mesh，重置为可见
        node.object3D.traverse((obj) => {
            if (obj.isMesh && !obj.visible) {
                obj.visible = true;
                resetCount++;
            }
        });
        
        if (resetCount > 0) {
        }
    }
    
    /**
     * 添加轮廓高亮效果
     * @param {THREE.Object3D} object - 3D对象
     */
    addOutlineEffect(object) {
        if (!object || !THREE) {
            return;
        }
        
        // 先移除之前的轮廓效果
        this.removeOutlineEffect();
        
        const manager = window._sceneManager;
        const currentScene = manager?.getCurrentScene();
        if (!currentScene || !currentScene.scene) {
            console.warn('⚠️ 无法添加轮廓：场景未初始化');
            return;
        }
        
        // 创建轮廓辅助对象（使用BoxHelper或边缘辅助）
        try {
            // 为对象创建包围盒辅助框
            const boxHelper = new THREE.BoxHelper(object, 0x00ff00); // 绿色轮廓
            boxHelper.material.linewidth = 2;
            currentScene.scene.add(boxHelper);
            
            this._outlineHelper = boxHelper;
            this._outlineTarget = object;
        } catch (error) {
            console.warn('⚠️ 添加轮廓效果失败:', error);
        }
    }
    
    /**
     * 移除轮廓高亮效果
     */
    removeOutlineEffect() {
        if (this._outlineHelper) {
            const manager = window._sceneManager;
            const currentScene = manager?.getCurrentScene();
            if (currentScene && currentScene.scene) {
                currentScene.scene.remove(this._outlineHelper);
                this._outlineHelper.dispose();
            }
            this._outlineHelper = null;
            this._outlineTarget = null;
        }
    }
    
    /**
     * 更新轮廓高亮效果（在对象移动/旋转/缩放时调用）
     */
    updateOutlineEffect() {
        if (this._outlineHelper && this._outlineTarget) {
            // BoxHelper 需要手动更新才能跟随对象移动
            this._outlineHelper.update();
        }
    }
    
    /**
     * 保存当前显示的所有mesh的原始transform
     * ⚠️ 只保存尚未缓存的mesh，避免覆盖真正的原始状态
     * @param {Array} meshList - mesh列表（可以是普通mesh树的节点，也可以是搜索结果）
     */
    saveCurrentMeshTransforms(meshList) {
        if (!meshList || meshList.length === 0) return;
        
        meshList.forEach(item => {
            const mesh = item.mesh || item;
            const node = item.node;
            
                if (mesh && mesh.isMesh) {
                    // ⭐ 使用mesh对象本身作为key，而不是UUID
                    // 这样即使两个节点有相同UUID的mesh，也会被分别保存
                    if (!this._meshOriginalTransforms.has(mesh)) {
                        // 获取局部坐标和世界坐标
                        const localPos = mesh.position.clone();
                        const worldPos = new THREE.Vector3();
                        mesh.getWorldPosition(worldPos);
                        
                        this._meshOriginalTransforms.set(mesh, {
                            position: localPos,
                            rotation: mesh.rotation.clone(),
                            scale: mesh.scale.clone(),
                            parentNode: node,
                            worldPosition: worldPos.clone()
                        });
                }
            }
        });
    }
    
    /**
     * 保存单个Mesh的原始状态（在选中时调用）
     * @param {Object} matchItem - 搜索匹配项 {node, mesh, path, nodeName}
     */
    saveMeshOriginalState(matchItem) {
        if (!matchItem || !matchItem.mesh || !matchItem.mesh.isMesh) return;
        
        const mesh = matchItem.mesh;
        
        // ⭐ 使用mesh对象本身作为key
        if (!this._meshOriginalTransforms.has(mesh)) {
            const currentPos = mesh.position.clone();
            this._meshOriginalTransforms.set(mesh, {
                position: currentPos,
                rotation: mesh.rotation.clone(),
                scale: mesh.scale.clone(),
                parentNode: matchItem.node // 记录所属节点
            });
        }
    }
    
    /**
     * 保存节点下所有mesh的原始transform状态
     * @param {TreeNode} node - 场景树节点
     * @param {boolean} forceReset - 是否强制重置所有保存状态（默认false）
     */
    saveAllMeshOriginalTransforms(node, forceReset = false) {
        if (!node || !node.object3D) return;
        
        // 只在切换节点或强制重置时才清空之前的保存状态
        const isSwitchingNode = this._currentMeshEditNode && this._currentMeshEditNode !== node;
        const isFirstEnter = !this._currentMeshEditNode;
        
        if (forceReset) {
            this._meshOriginalTransforms.clear();
        } else if (isSwitchingNode) {
            this._meshOriginalTransforms.clear();
        }
        
        let savedCount = 0;
        
        // 1. 遍历当前节点下的所有mesh并保存transform（只保存尚未保存的）
        node.object3D.traverse((child) => {
            if (child.isMesh) {
                // ⭐ 使用mesh对象本身作为key
                if (!this._meshOriginalTransforms.has(child)) {
                    // 保存当前位置
                    const currentPos = child.position.clone();
                    this._meshOriginalTransforms.set(child, {
                        position: currentPos,
                        rotation: child.rotation.clone(),
                        scale: child.scale.clone(),
                        parentNode: node // 记录所属节点
                    });
                    console.log(`  💾 保存Mesh: ${child.name || '未命名'} (${child.uuid.substring(0, 8)}...)`);
                    console.log(`     当前位置: (${currentPos.x.toFixed(2)}, ${currentPos.y.toFixed(2)}, ${currentPos.z.toFixed(2)})`);
                    savedCount++;
                } else {
                    const saved = this._meshOriginalTransforms.get(child);
                    console.log(`  ⏭️ 跳过已保存的Mesh: ${child.name || '未命名'} (${child.uuid.substring(0, 8)}...)`);
                    console.log(`     已保存位置: (${saved.position.x.toFixed(2)}, ${saved.position.y.toFixed(2)}, ${saved.position.z.toFixed(2)})`);
                    console.log(`     当前位置: (${child.position.x.toFixed(2)}, ${child.position.y.toFixed(2)}, ${child.position.z.toFixed(2)})`);
                }
            }
        });
        
        // 2. 如果在搜索模式下有选中的Mesh，也要保存它们的状态
        if (this.meshSearchKeyword && this.selectedMeshes.length > 0) {
            let newlySaved = 0;
            this.selectedMeshes.forEach(matchItem => {
                const mesh = matchItem.mesh;
                // ⭐ 使用mesh对象本身作为key
                if (mesh && mesh.isMesh && !this._meshOriginalTransforms.has(mesh)) {
                    this._meshOriginalTransforms.set(mesh, {
                        position: mesh.position.clone(),
                        rotation: mesh.rotation.clone(),
                        scale: mesh.scale.clone(),
                        parentNode: matchItem.node // 记录所属节点
                    });
                    newlySaved++;
                }
            });
        }
        
        // 保存当前mesh编辑的节点
        this._currentMeshEditNode = node;
    }
    
    /**
     * 恢复节点下所有mesh的原始transform状态
     * @param {TreeNode} node - 场景树节点（可选，默认使用当前mesh编辑节点）
     * @param {boolean} clearState - 是否清空保存的状态（默认false，不清空）
     */
    restoreAllMeshOriginalTransforms(node = null, clearState = false) {
        if (this._meshOriginalTransforms.size === 0) {
            console.warn('⚠️ 没有保存的mesh原始transform');
            return;
        }
        
        let restoredCount = 0;
        const restoredNodes = new Set();
        
        // 方法1：如果指定了节点，只恢复该节点下的Mesh
        if (node && node.object3D) {
            node.object3D.traverse((child) => {
                // ⭐ 使用mesh对象本身作为key
                if (child.isMesh && this._meshOriginalTransforms.has(child)) {
                    const originalTransform = this._meshOriginalTransforms.get(child);
                    
                    console.log(`  ↩️ 恢复Mesh: ${child.name || '未命名'} (${child.uuid.substring(0, 8)}...)`);
                    
                    child.position.copy(originalTransform.position);
                    child.rotation.copy(originalTransform.rotation);
                    child.scale.copy(originalTransform.scale);
                    
                    // 强制更新矩阵
                    child.updateMatrix();
                    child.updateMatrixWorld(true);
                    
                    restoredCount++;
                    restoredNodes.add(node.name);
                }
            });
        } 
        // 方法2：恢复所有保存的Mesh（包括搜索模式下的跨节点Mesh）
        else {
            // ⭐ 遍历所有保存的Mesh并恢复（key就是mesh对象本身）
            this._meshOriginalTransforms.forEach((originalTransform, mesh) => {
                // mesh就是key，直接使用
                
                if (mesh && mesh.isMesh) {
                    // 🔧 【关键修复】通过世界坐标恢复mesh位置
                    // 1. 先恢复世界位置
                    if (originalTransform.worldPosition && mesh.parent) {
                        // 将世界坐标转换为父对象坐标系下的局部坐标
                        const targetWorldPos = originalTransform.worldPosition.clone();
                        const parentWorldMatrix = new THREE.Matrix4();
                        mesh.parent.updateMatrixWorld(true);
                        parentWorldMatrix.copy(mesh.parent.matrixWorld);
                        
                        // 计算父对象的逆矩阵
                        const parentInverseMatrix = new THREE.Matrix4();
                        parentInverseMatrix.copy(parentWorldMatrix).invert();
                        
                        // 将世界坐标转换到父对象的局部坐标系
                        const localPos = targetWorldPos.clone();
                        localPos.applyMatrix4(parentInverseMatrix);
                        
                        // 设置局部坐标
                        mesh.position.copy(localPos);
                    } else {
                        // 没有世界坐标或没有父对象，直接使用保存的局部坐标
                        mesh.position.copy(originalTransform.position);
                    }
                    
                    // 2. 恢复旋转和缩放
                    mesh.rotation.copy(originalTransform.rotation);
                    mesh.scale.copy(originalTransform.scale);
                    
                    // 3. 强制更新矩阵
                    mesh.updateMatrix();
                    mesh.updateMatrixWorld(true);
                    
                    restoredCount++;
                    if (originalTransform.parentNode) {
                        restoredNodes.add(originalTransform.parentNode.name);
                    }
                }
            });
        }
        
        // 根据参数决定是否清空保存的状态
        if (clearState) {
            this._meshOriginalTransforms.clear();
            this._currentMeshEditNode = null;
        }
        
        // 强制多次渲染，确保变换立即生效
        const currentScene = window.manager?.getCurrentScene();
        if (currentScene && currentScene.renderer) {
            // 立即渲染一次
            currentScene.renderer.render(currentScene.scene, currentScene.camera);
            
            // 再渲染几帧以确保更新生效
            requestAnimationFrame(() => {
                currentScene.renderer.render(currentScene.scene, currentScene.camera);
                requestAnimationFrame(() => {
                    currentScene.renderer.render(currentScene.scene, currentScene.camera);
                });
            });
        }
    }
    
    /**
     * 重置当前节点所有mesh的transform（恢复到保存的原始状态）
     */
    resetCurrentMeshTransform() {
        if (!this._currentMeshEditNode) {
            console.warn('⚠️ 没有处于mesh编辑模式的节点');
            return;
        }
        
        // ⚠️ 关键修复：先detach TransformControls，避免它干扰mesh位置恢复
        const currentScene = window.manager?.getCurrentScene();
        if (currentScene && currentScene.transformControlsManager) {
            currentScene.transformControlsManager.detach();
        }
        
        // 清除选中的mesh引用，避免干扰
        this._currentSelectedMesh = null;
        
        // 1. 直接恢复所有mesh的原始变换（不清空状态，以便可以再次重置）
        this.restoreAllMeshOriginalTransforms(null, false);
        
        // 2. 清除选中的Mesh和轮廓
        if (this.meshSearchKeyword && this.selectedMeshes.length > 0) {
            // 清除搜索结果的选中样式
            const meshPanel = document.getElementById('mesh-structure-panel');
            if (meshPanel) {
                meshPanel.querySelectorAll('.mesh-search-result-item.selected').forEach(item => {
                    item.classList.remove('selected');
                });
            }
            this.selectedMeshes = [];
        }
        
        // 清除普通mesh树中的选中状态
        const meshPanel = document.getElementById('mesh-structure-panel');
        if (meshPanel) {
            meshPanel.querySelectorAll('.mesh-tree-node.selected').forEach(n => {
                n.classList.remove('selected');
            });
        }
        
        // 3. 移除轮廓效果
        this.removeOutlineEffect();
        
        // 4. 清除F键聚焦目标
        this._focusTarget = null;
        this._focusTargetType = null;
    }
    
    /**
     * 显示Mesh材质对话框
     * @param {HTMLElement} button - 点击的材质按钮
     */
    async showMeshMaterialDialog(button) {
        const meshUuid = button.dataset.uuid;
        const nodeId = button.dataset.nodeId;
        
        if (!meshUuid) {
            console.warn('⚠️ 按钮缺少mesh UUID');
            return;
        }
        
        // 从按钮获取节点ID，然后查找节点
        let sceneNode = null;
        
        if (nodeId) {
            // 优先使用按钮上保存的节点ID
            sceneNode = this.treeManager.findNodeById(nodeId);
        }
        
        // ⚠️ 在mesh模式下，场景树的selectedNode会被清空，所以优先使用mesh编辑模式的节点
        if (!sceneNode && this._currentMeshEditNode) {
            sceneNode = this._currentMeshEditNode;
        }
        
        // 如果还是没有，尝试使用当前选中的节点（非mesh模式）
        if (!sceneNode && this.treeManager.selectedNode) {
            sceneNode = this.treeManager.selectedNode;
        }
        
        if (!sceneNode) {
            console.error('❌ 无法找到节点！请确保已选中节点或节点数据正确');
            alert('无法找到节点信息，请先选中一个节点');
            return;
        }
        
        // 在场景中查找对应的mesh对象
        const meshObject = sceneNode.object3D.getObjectByProperty('uuid', meshUuid);
        if (!meshObject || !meshObject.isMesh) {
            console.warn('⚠️ 未找到对应的Mesh对象');
            return;
        }
        // 检查材质是否是默认材质
        const material = meshObject.material;
        if (!material) {
            alert('该Mesh没有材质');
            return;
        }
        
        // 检查mesh是否已经绑定了材质库的材质
        let boundMaterialId = null;
        
        // 1. 优先从mesh材质的userData中获取materialId
        if (material.userData && material.userData.materialId) {
            boundMaterialId = material.userData.materialId;
        }
        
        // 2. 如果没有，从节点的model组件中获取
        if (!boundMaterialId && sceneNode.components?.model?.meshMaterials) {
            // 先尝试用uuid查找，如果找不到再用name查找（兼容两种存储方式）
            let meshMaterialData = sceneNode.components.model.meshMaterials[meshUuid];
            if (!meshMaterialData && meshObject.name) {
                meshMaterialData = sceneNode.components.model.meshMaterials[meshObject.name];
            }
            if (meshMaterialData && meshMaterialData.materialId) {
                boundMaterialId = meshMaterialData.materialId;
            }
        }
        
        // 如果mesh已经绑定了材质库的材质，直接打开材质编辑器
        if (boundMaterialId) {
            await this.openMaterialEditorWithMaterial(boundMaterialId);
            return;
        }
        
        // 如果没有绑定材质，显示创建材质对话框
        const materialInfo = this.getMaterialInfo(material);
        
        // 🎯 获取mesh的材质名（优先从节点组件中的源材质名）
        let meshMaterialName = null;
        const meshName = meshObject.name;
        
        // 1. 尝试从场景节点的模型组件中获取（使用mesh name作为key）
        if (sceneNode.components && Array.isArray(sceneNode.components)) {
            const modelComponent = sceneNode.components.find(c => c.type === 'model');
            if (modelComponent?.meshMaterials && meshName) {
                const meshMaterialData = modelComponent.meshMaterials[meshName];
                if (meshMaterialData && typeof meshMaterialData === 'string') {
                    // ✅ 新架构：直接是字符串
                    meshMaterialName = meshMaterialData;
                }
            }
        }
        
        // 2. 如果节点中没有，从模型库中读取
        if (!meshMaterialName && sceneNode.components) {
            const modelComponent = sceneNode.components.find(c => c.type === 'model');
            if (modelComponent?.modelId) {
                const modelId = modelComponent.modelId;
                const modelType = modelComponent.modelType || 'model'; // 🎯 获取模型类型
                try {
                    const currentProject = window.projectManager?.getCurrentProject();
                    if (currentProject) {
                        // 🎯 添加 type 参数以支持节点模型
                        const typeParam = modelType === 'node' ? '?type=node' : '';
                        const response = await fetch(`/api/projects/${currentProject.id}/models/${modelId}${typeParam}`);
                        if (response.ok) {
                            const result = await response.json();
                            if (result.success && result.data?.meshMaterials && meshName) {
                                const modelMeshData = result.data.meshMaterials[meshName];
                                if (modelMeshData && typeof modelMeshData === 'string') {
                                    // ✅ 新架构：直接是材质名（字符串）
                                    meshMaterialName = modelMeshData;
                                }
                            }
                        }
                    }
                } catch (error) {
                    console.warn('   - 从模型库获取材质名失败:', error);
                }
            }
        }
        
        await this.showCreateEditableMaterialDialog(meshObject, materialInfo, sceneNode, meshMaterialName);
    }
    
    /**
     * 打开材质编辑器并选中指定材质
     * @param {string} materialId - 材质ID
     */
    async openMaterialEditorWithMaterial(materialId) {
        try {
            // 获取右侧工具栏管理器
            const rightToolbarManager = window.rightToolbarManager;
            if (!rightToolbarManager) {
                console.error('❌ 无法访问rightToolbarManager');
                alert('无法打开材质编辑器');
                return;
            }
            
            // 切换到材质编辑器标签页
            await rightToolbarManager.openPanel('material-editor');
            
            // 等待材质编辑器初始化
            await new Promise(resolve => setTimeout(resolve, 200));
            
            // 获取材质编辑器实例
            const materialEditorPanel = rightToolbarManager.materialEditorPanel;
            if (!materialEditorPanel) {
                console.error('❌ 材质编辑器面板未初始化');
                alert('材质编辑器初始化失败');
                return;
            }
            
            // 选中指定的材质
            await materialEditorPanel.selectMaterial(materialId);
            // 显示提示消息
            if (window.showManageMessage) {
                window.showManageMessage('已在材质编辑器中打开该材质', 'success');
            }
            
        } catch (error) {
            console.error('❌ 打开材质编辑器失败:', error);
            alert('打开材质编辑器失败: ' + error.message);
        }
    }
    
    /**
     * 获取材质信息
     * @param {THREE.Material} material - Three.js材质对象
     * @returns {Object} 材质信息
     */
    getMaterialInfo(material) {
        const info = {
            type: material.type,
            color: material.color ? `#${material.color.getHexString()}` : '#ffffff',
            opacity: material.opacity !== undefined ? material.opacity : 1.0,
            transparent: material.transparent || false,
            side: material.side
        };
        
        // ⭐ 提取贴图信息
        const textureProperties = ['map', 'normalMap', 'bumpMap', 'aoMap', 'emissiveMap', 
                                   'metalnessMap', 'roughnessMap', 'specularMap', 'displacementMap'];
        
        textureProperties.forEach(prop => {
            if (material[prop]) {
                info[prop] = material[prop]; // 保存贴图引用
            }
        });
        
        // 提取贴图强度参数
        if (material.aoMapIntensity !== undefined) {
            info.aoMapIntensity = material.aoMapIntensity;
        }
        if (material.bumpScale !== undefined) {
            info.bumpScale = material.bumpScale;
        }
        if (material.normalScale) {
            info.normalScale = {
                x: material.normalScale.x,
                y: material.normalScale.y
            };
        }
        if (material.displacementScale !== undefined) {
            info.displacementScale = material.displacementScale;
        }
        if (material.displacementBias !== undefined) {
            info.displacementBias = material.displacementBias;
        }
        
        // 根据材质类型添加特定属性
        if (material.type === 'MeshStandardMaterial' || material.type === 'MeshPhysicalMaterial') {
            info.metalness = material.metalness !== undefined ? material.metalness : 0.5;
            info.roughness = material.roughness !== undefined ? material.roughness : 0.5;
            info.emissive = material.emissive ? `#${material.emissive.getHexString()}` : '#000000';
            info.emissiveIntensity = material.emissiveIntensity !== undefined ? material.emissiveIntensity : 0;
            
            // ⭐ MeshPhysicalMaterial 特有属性
            if (material.type === 'MeshPhysicalMaterial') {
                info.clearcoat = material.clearcoat !== undefined ? material.clearcoat : 0;
                info.clearcoatRoughness = material.clearcoatRoughness !== undefined ? material.clearcoatRoughness : 0;
                info.reflectivity = material.reflectivity !== undefined ? material.reflectivity : 0.5;
                info.sheen = material.sheen !== undefined ? material.sheen : 0;
                info.transmission = material.transmission !== undefined ? material.transmission : 0;
                info.thickness = material.thickness !== undefined ? material.thickness : 0;
                info.ior = material.ior !== undefined ? material.ior : 1.5;
            }
        } else if (material.type === 'MeshPhongMaterial') {
            info.shininess = material.shininess !== undefined ? material.shininess : 30;
            info.emissive = material.emissive ? `#${material.emissive.getHexString()}` : '#000000';
            info.specular = material.specular ? `#${material.specular.getHexString()}` : '#111111';
        } else if (material.type === 'MeshLambertMaterial') {
            info.emissive = material.emissive ? `#${material.emissive.getHexString()}` : '#000000';
        }
        
        return info;
    }
    
    /**
     * 显示创建可编辑材质对话框
     * @param {THREE.Mesh} meshObject - Mesh对象
     * @param {Object} materialInfo - 材质信息
     * @param {TreeNode} node - 包含此mesh的场景树节点
     * @param {string} meshMaterialName - Mesh的FBX材质名（可选）
     */
    async showCreateEditableMaterialDialog(meshObject, materialInfo, node, meshMaterialName = null) {
        // 生成默认材质名称（优先使用FBX的材质名）
        const defaultMaterialName = meshMaterialName || `${meshObject.name || 'Mesh'}_Material`;
        // 检查材质名称是否已存在
        const projectId = window.projectManager?.getCurrentProject()?.id;
        let isDuplicate = false;
        let existingMaterials = [];
        
        if (projectId) {
            const materialLibraryManager = getMaterialLibraryManager(projectId);
            await materialLibraryManager.loadMaterials();
            existingMaterials = materialLibraryManager.materials || [];
            isDuplicate = existingMaterials.some(m => 
                (m.displayName || m.name) === defaultMaterialName
            );
        }
        
        // 创建模态框HTML
        const modalHtml = `
            <div class="material-modal active" id="create-editable-material-modal">
                <div class="material-modal-content">
                    <div class="material-modal-header">
                        <h3>创建可编辑材质</h3>
                        <button class="material-modal-close" onclick="window.sceneTreeUI.closeCreateEditableMaterialDialog()">×</button>
                    </div>
                    <div class="material-modal-body">
                        <div class="material-info-text">
                            <p><strong>⚠️ Mesh默认材质无法直接编辑</strong></p>
                            <p>该Mesh当前使用的是模型文件中的默认材质，无法直接修改。</p>
                            <p>请为此Mesh创建一个可编辑的材质副本：</p>
                        </div>
                        
                        <div class="material-form-group">
                            <label>材质名称 <span class="required">*</span></label>
                            <input type="text" id="editable-material-name" value="${defaultMaterialName}" placeholder="例如：红色金属、玻璃材质等" />
                            <div class="material-form-hint" id="material-name-hint" style="color: ${isDuplicate ? '#ff6b6b' : 'rgba(255, 255, 255, 0.5)'}">
                                ${isDuplicate ? '⚠️ 该材质名称已存在，请修改后再创建' : '将创建基于物理的渲染材质（Physical Material）'}
                            </div>
                        </div>
                        
                        <div class="material-info-box">
                            <h4>当前材质信息</h4>
                            <table class="material-info-table">
                                <tr>
                                    <td>Mesh名称</td>
                                    <td><strong>${meshObject.name || '(unnamed)'}</strong></td>
                                </tr>
                                <tr>
                                    <td>材质类型</td>
                                    <td>${materialInfo.type}</td>
                                </tr>
                                <tr>
                                    <td>颜色</td>
                                    <td>
                                        <span class="color-preview" style="background: ${materialInfo.color}"></span>
                                        ${materialInfo.color}
                                    </td>
                                </tr>
                                ${materialInfo.metalness !== undefined ? `
                                <tr>
                                    <td>金属度</td>
                                    <td>${materialInfo.metalness.toFixed(2)}</td>
                                </tr>
                                <tr>
                                    <td>粗糙度</td>
                                    <td>${materialInfo.roughness.toFixed(2)}</td>
                                </tr>
                                ` : ''}
                                <tr>
                                    <td>透明度</td>
                                    <td>${materialInfo.opacity.toFixed(2)}</td>
                                </tr>
                            </table>
                        </div>
                    </div>
                    <div class="material-modal-footer">
                        <button class="material-btn-secondary" onclick="window.sceneTreeUI.closeCreateEditableMaterialDialog()">取消</button>
                        <button class="material-btn-primary" id="confirm-create-editable-material" ${isDuplicate ? 'disabled' : ''}>创建材质</button>
                    </div>
                </div>
            </div>
        `;
        
        // 添加到body
        const existingModal = document.getElementById('create-editable-material-modal');
        if (existingModal) {
            existingModal.remove();
        }
        
        document.body.insertAdjacentHTML('beforeend', modalHtml);
        
        // 保存Mesh和节点引用以及现有材质列表
        this._currentEditMaterialMesh = meshObject;
        this._currentEditMaterialNode = node;
        this._existingMaterials = existingMaterials;
        
        // 绑定材质名称输入框的实时检查
        const nameInput = document.getElementById('editable-material-name');
        const confirmBtn = document.getElementById('confirm-create-editable-material');
        const hintEl = document.getElementById('material-name-hint');
        
        if (nameInput && confirmBtn && hintEl) {
            nameInput.addEventListener('input', () => {
                const newName = nameInput.value.trim();
                const isNameDuplicate = this._existingMaterials.some(m => 
                    (m.displayName || m.name) === newName
                );
                
                if (!newName) {
                    hintEl.textContent = '⚠️ 请输入材质名称';
                    hintEl.style.color = '#ff6b6b';
                    confirmBtn.disabled = true;
                } else if (isNameDuplicate) {
                    hintEl.textContent = '⚠️ 该材质名称已存在，请修改后再创建';
                    hintEl.style.color = '#ff6b6b';
                    confirmBtn.disabled = true;
                } else {
                    hintEl.textContent = '将创建基于物理的渲染材质（Physical Material）';
                    hintEl.style.color = 'rgba(255, 255, 255, 0.5)';
                    confirmBtn.disabled = false;
                }
            });
            
            // 绑定确认按钮
            confirmBtn.addEventListener('click', () => {
                window.sceneTreeUI.confirmCreateEditableMaterial(meshObject.uuid);
            });
        }
    }
    
    /**
     * 关闭创建可编辑材质对话框
     */
    closeCreateEditableMaterialDialog() {
        const modal = document.getElementById('create-editable-material-modal');
        if (modal) {
            modal.remove();
        }
        this._currentEditMaterialMesh = null;
        this._currentEditMaterialNode = null;
    }
    
    /**
     * 确认创建可编辑材质
     * @param {string} meshUuid - Mesh UUID
     */
    async confirmCreateEditableMaterial(meshUuid) {
        if (!this._currentEditMaterialMesh || !this._currentEditMaterialNode) {
            console.error('❌ 没有保存的Mesh或节点引用');
            return;
        }
        
        try {
            const meshObject = this._currentEditMaterialMesh;
            const node = this._currentEditMaterialNode;
            const originalMaterial = meshObject.material;
            // 1. 获取用户输入的材质名称
            const nameInput = document.getElementById('editable-material-name');
            const displayName = nameInput ? nameInput.value.trim() : `${meshObject.name || 'Mesh'}_Material`;
            
            if (!displayName) {
                if (window.showManageMessage) {
                    window.showManageMessage('请输入材质名称', 'warning');
                } else {
                    alert('请输入材质名称');
                }
                return;
            }
            
            // 2. 从当前材质复制参数
            const materialInfo = this.getMaterialInfo(originalMaterial);
            
            // 3. 生成唯一的材质ID
            const timestamp = Date.now();
            const random = Math.random().toString(36).substring(2, 8);
            const materialId = `material_${timestamp}_${random}`;
            // 4. 获取项目ID并创建材质库管理器
            const projectId = window.projectManager?.getCurrentProject()?.id;
            if (!projectId) {
                throw new Error('无法获取项目ID');
            }
            
            const materialLibraryManager = getMaterialLibraryManager(projectId);
            
            // 5. ⭐ 再次检查材质名称是否已存在（双重验证）
            await materialLibraryManager.loadMaterials();
            const existingMaterials = materialLibraryManager.materials || [];
            const isDuplicate = existingMaterials.some(m => 
                (m.displayName || m.name) === displayName
            );
            
            if (isDuplicate) {
                console.warn('⚠️ 材质名称已存在:', displayName);
                
                // 显示错误消息但不关闭对话框，让用户修改名称
                if (window.showManageMessage) {
                    window.showManageMessage(`材质名称 "${displayName}" 已存在，请修改后再试`, 'error');
                } else {
                    alert(`材质名称 "${displayName}" 已存在，请修改后再试`);
                }
                
                // 更新提示文本
                const hintEl = document.getElementById('material-name-hint');
                if (hintEl) {
                    hintEl.textContent = '⚠️ 该材质名称已存在，请修改后再创建';
                    hintEl.style.color = '#ff6b6b';
                }
                
                // 禁用创建按钮
                const confirmBtn = document.getElementById('confirm-create-editable-material');
                if (confirmBtn) {
                    confirmBtn.disabled = true;
                }
                
                return;
            }
            // 6. 构建材质数据
            // ⭐ 默认创建 MeshPhysicalMaterial（物理材质），兼容所有PBR特性
            const materialData = {
                name: materialId,
                displayName: displayName,
                type: 'MeshPhysicalMaterial', // ⭐ 强制使用物理材质
                description: `从 ${meshObject.name || 'Mesh'} 创建的材质`,
                color: materialInfo.color,
                opacity: materialInfo.opacity,
                doubleSided: materialInfo.side === THREE.DoubleSide,
                // ⭐ 复制PBR参数
                metalness: materialInfo.metalness !== undefined ? materialInfo.metalness : 0.5,
                roughness: materialInfo.roughness !== undefined ? materialInfo.roughness : 0.5,
                emissive: materialInfo.emissive || '#000000',
                emissiveIntensity: materialInfo.emissiveIntensity !== undefined ? materialInfo.emissiveIntensity : 0,
                // ⭐ 贴图强度参数
                aoMapIntensity: materialInfo.aoMapIntensity !== undefined ? materialInfo.aoMapIntensity : 1.0,
                bumpScale: materialInfo.bumpScale !== undefined ? materialInfo.bumpScale : 1.0,
                displacementScale: materialInfo.displacementScale !== undefined ? materialInfo.displacementScale : 1.0,
                displacementBias: materialInfo.displacementBias !== undefined ? materialInfo.displacementBias : 0,
                // ⭐ MeshPhysicalMaterial 特有属性
                clearcoat: materialInfo.clearcoat !== undefined ? materialInfo.clearcoat : 0,
                clearcoatRoughness: materialInfo.clearcoatRoughness !== undefined ? materialInfo.clearcoatRoughness : 0,
                reflectivity: materialInfo.reflectivity !== undefined ? materialInfo.reflectivity : 0.5,
                sheen: materialInfo.sheen !== undefined ? materialInfo.sheen : 0,
                transmission: materialInfo.transmission !== undefined ? materialInfo.transmission : 0,
                thickness: materialInfo.thickness !== undefined ? materialInfo.thickness : 0,
                ior: materialInfo.ior !== undefined ? materialInfo.ior : 1.5
            };
            
            // ⭐ 保存贴图引用（用于创建Three.js材质时应用）
            materialData._textures = {};
            const textureProperties = ['map', 'normalMap', 'bumpMap', 'aoMap', 'emissiveMap', 
                                       'metalnessMap', 'roughnessMap', 'specularMap', 'displacementMap'];
            textureProperties.forEach(prop => {
                if (materialInfo[prop]) {
                    materialData._textures[prop] = materialInfo[prop];
                }
            });
            
            // 法线贴图缩放
            if (materialInfo.normalScale) {
                materialData.normalScaleX = materialInfo.normalScale.x;
                materialData.normalScaleY = materialInfo.normalScale.y;
            }
            
            // 7. 创建材质到材质库
            const createdMaterial = await materialLibraryManager.createMaterial(materialData);
            // 8. 将新创建的材质应用到Mesh
            // 保存并释放旧材质
            const oldMaterial = meshObject.material;
            
            // 创建Three.js材质对象
            const newThreeMaterial = this.createThreeMaterialFromData(materialData);
            
            // 保存材质ID到材质对象的userData
            newThreeMaterial.userData.materialId = createdMaterial.id;
            newThreeMaterial.userData.materialName = materialData.name;
            
            // 应用到mesh
            meshObject.material = newThreeMaterial;
            
            // 标记mesh和材质需要更新
            meshObject.material.needsUpdate = true;
            if (meshObject.geometry) {
                meshObject.geometry.attributes.position.needsUpdate = true;
            }
            
            // 释放旧材质资源
            if (oldMaterial && oldMaterial !== newThreeMaterial) {
                // 不立即dispose，因为可能被其他mesh共享
            }
            // 9. 保存材质绑定到节点的model组件数据
            // ✅ 新架构：使用 displayName 作为标识
            await this.saveMeshMaterialBinding(node, meshObject, createdMaterial.displayName);
            
            // ⭐ 10. 更新材质引用到后端
            const sceneId = window.manager?.getCurrentSceneName();
            if (projectId && sceneId) {
                try {
                    const { addMaterialReference } = await import('../utils/materialReferenceHelper.js');
                    await addMaterialReference(
                        projectId, 
                        createdMaterial.displayName, 
                        sceneId, 
                        node.id, 
                        meshObject.name, 
                        meshObject.name
                    );
                    console.log('✅ [SceneTreeUI] 材质引用已更新');
                    
                    // 刷新材质面板（如果存在）
                    if (window.materialEditorPanel && window.materialEditorPanel.refreshMaterialUsageAfterNodeChange) {
                        setTimeout(async () => {
                            await window.materialEditorPanel.refreshMaterialUsageAfterNodeChange();
                        }, 200);
                    }
                } catch (error) {
                    console.warn('⚠️ [SceneTreeUI] 更新材质引用失败:', error);
                }
            }
            
            // 11. 关闭对话框
            this.closeCreateEditableMaterialDialog();
            
            // 12. 刷新mesh面板显示
            if (this.treeManager.selectedNode) {
                this.updateMeshStructurePanel(this.treeManager.selectedNode);
            }
            
            // 13. 显示成功消息
            const message = `材质 "${displayName}" 创建成功并已应用到 ${meshObject.name || 'Mesh'}！`;
            if (window.showManageMessage) {
                window.showManageMessage(message, 'success');
            } else {
                alert(message);
            }
            // 13. ⭐ 自动打开材质编辑器并选中新创建的材质
            await this.openMaterialEditorWithMaterial(createdMaterial.id);
        } catch (error) {
            console.error('❌ 创建可编辑材质失败:', error);
            
            // 关闭对话框
            this.closeCreateEditableMaterialDialog();
            
            // 显示错误消息
            const errorMessage = '创建材质失败: ' + error.message;
            if (window.showManageMessage) {
                window.showManageMessage(errorMessage, 'error');
            } else {
                alert(errorMessage);
            }
        }
    }
    
    /**
     * 自动修复节点中的透明材质 - Alpha优先策略
     * @param {TreeNode} node - 场景树节点
     */
    autoFixDarkTransparentMaterials(node) {
        if (!node.object3D) return;
        
        let fixedCount = 0;
        
        node.object3D.traverse((obj) => {
            if (obj.isMesh && obj.material) {
                const materials = Array.isArray(obj.material) ? obj.material : [obj.material];
                
                materials.forEach((mat) => {
                    // 🎯 Alpha优先策略：检查是否为透明材质
                    const hasAlphaTransparency = mat.transparent || mat.alphaTest > 0 || mat.opacity < 1 || !!mat.alphaMap;
                    
                    if (hasAlphaTransparency) {
                        console.log(`🔧 [UI Alpha优先修复] 透明材质: ${obj.name} - ${mat.userData?.materialName || mat.name}`);
                        console.log(`   修复前: RGB(${mat.color.r.toFixed(3)}, ${mat.color.g.toFixed(3)}, ${mat.color.b.toFixed(3)}), opacity=${mat.opacity}, alphaTest=${mat.alphaTest}`);
                        
                        // 🔑 关键策略：alpha值为透明时，基础颜色设为白色，让alpha通道主导
                        const hasAlpha = mat.opacity < 1 || mat.alphaTest > 0 || !!mat.alphaMap;
                        
                        if (hasAlpha) {
                            // 有alpha设置时，基础颜色设为白色，不干扰alpha效果
                            mat.color.setRGB(1.0, 1.0, 1.0);
                            // 🔧 关键修复：强制触发材质更新，确保颜色变化立即生效
                            mat.needsUpdate = true;
                            console.log(`   🎨 Alpha优先策略：基础颜色设为白色，强制更新材质`);
                        }
                        
                        // 🎯 根据透明类型设置正确的参数
                        const matName = (mat.userData?.materialName || mat.name || '').toLowerCase();
                        const meshName = (obj.name || '').toLowerCase();
                        const isRoadLine = matName.includes('马路') || matName.includes('线') || 
                                         meshName.includes('马路') || meshName.includes('线') ||
                                         matName.includes('road') || matName.includes('line');
                        
                        if (mat.opacity < 1) {
                            // opacity透明模式：以opacity值为准
                            mat.transparent = true;
                            mat.alphaTest = 0;
                            mat.depthWrite = false;
                            mat.depthTest = true;
                            obj.renderOrder = isRoadLine ? 100 : 999;
                            console.log(`   🔧 opacity透明模式：opacity=${mat.opacity}, renderOrder=${obj.renderOrder}`);
                            
                        } else if (mat.alphaTest > 0 || mat.alphaMap) {
                            // alphaTest透明模式：硬边透明
                            if (isRoadLine) {
                                mat.transparent = false;
                                mat.alphaTest = Math.max(0.1, mat.alphaTest || 0.5);
                                mat.depthWrite = true;
                                mat.depthTest = true;
                                obj.renderOrder = 100;
                                console.log(`   🛣️ 马路线alphaTest模式：alphaTest=${mat.alphaTest}`);
                            } else {
                                mat.transparent = false;
                                mat.alphaTest = mat.alphaTest || 0.5;
                                mat.depthWrite = true;
                                mat.depthTest = true;
                                obj.renderOrder = 200;
                                console.log(`   🔧 alphaTest透明模式：alphaTest=${mat.alphaTest}`);
                            }
                            
                        } else if (mat.transparent) {
                            // 纯transparent模式
                            mat.alphaTest = 0;
                            mat.depthWrite = false;
                            mat.depthTest = true;
                            obj.renderOrder = 999;
                            console.log(`   🔧 transparent模式：基础颜色白色化`);
                        }
                        
                        mat.needsUpdate = true;
                        fixedCount++;
                        
                        console.log(`   ✅ Alpha优先修复完成: RGB(${mat.color.r.toFixed(3)}, ${mat.color.g.toFixed(3)}, ${mat.color.b.toFixed(3)})`);
                        console.log(`   💡 原理：alpha值主导透明效果，基础颜色和贴图RGB影响降低`);
                    }
                });
            }
        });
        
        if (fixedCount > 0) {
            console.log(`🎨 [UI Alpha优先修复] 节点 "${node.name}" 修复了 ${fixedCount} 个透明材质`);
            
            // 触发渲染更新
            if (window.manager && window.manager.render) {
                window.manager.render();
            }
        }
    }
    
    /**
     * 从节点的model组件数据加载并应用Mesh材质绑定
     * @param {TreeNode} node - 场景树节点
     */
    async loadMeshMaterialBindings(node) {
        try {
            // ✅ 修复：node.components是数组，需要用find查找
            if (!node.components || !Array.isArray(node.components)) {
                return;
            }
            
            // 获取节点的model组件
            const modelComponent = node.components.find(c => c.type === 'model');
            if (!modelComponent || !modelComponent.meshMaterials) {
                return; // 没有保存的材质绑定
            }
            // 获取项目ID和材质库管理器
            const projectId = window.projectManager?.getCurrentProject()?.id;
            if (!projectId) {
                console.warn('   ⚠️ 无法获取项目ID');
                return;
            }
            
            const materialLibraryManager = getMaterialLibraryManager(projectId);
            
            // 遍历所有保存的mesh材质绑定
            const meshMaterials = modelComponent.meshMaterials;
            let appliedCount = 0;
            
            // ✅ 新架构：根据 materialName（displayName）加载材质
            // meshMaterials格式：{ "meshName": "materialName" }
            for (const [meshName, materialName] of Object.entries(meshMaterials)) {
                try {
                    // 在场景中查找对应的mesh（使用name匹配）
                    const meshObject = node.object3D.getObjectByName(meshName);
                    if (!meshObject || !meshObject.isMesh) {
                        console.warn(`   ⚠️ 未找到Mesh (name: ${meshName})`);
                        continue;
                    }
                    
                    // ✅ 检查 materialName 是否存在（兼容旧格式）
                    const matName = typeof materialName === 'string' ? materialName : materialName?.materialName;
                    if (!matName) {
                        continue;
                    }
                    
                    // 从材质库加载材质数据（使用 displayName）
                    const materialData = await materialLibraryManager.getMaterial(matName);
                    if (!materialData) {
                        console.warn(`   ⚠️ 材质不存在 (name: ${matName})`);
                        continue;
                    }
                    
                    // 创建并应用材质
                    const material = this.createThreeMaterialFromData(materialData);
                    material.userData.materialName = materialData.displayName;
                    
                    meshObject.material = material;
                    meshObject.material.needsUpdate = true;
                    
                    appliedCount++;
                } catch (error) {
                    console.error(`   ❌ 应用材质失败 (mesh: ${meshName}):`, error);
                }
            }
            
            if (appliedCount > 0) {
                // 🎨 自动修复暗色透明材质（在材质绑定完成后）
                this.autoFixDarkTransparentMaterials(node);
            }
            
        } catch (error) {
            console.error('❌ 加载材质绑定失败:', error);
        }
    }
    
    /**
     * 保存Mesh材质绑定到节点的model组件数据
     * @param {TreeNode} node - 场景树节点
     * @param {THREE.Mesh} meshObject - Mesh对象
     * @param {string} materialName - 材质显示名称（displayName）
     */
    async saveMeshMaterialBinding(node, meshObject, materialName) {
        try {
            if (!node) {
                console.warn('   ⚠️ 节点参数为空，跳过保存');
                return;
            }
            
            // ✅ 修复：node.components是数组，需要用find查找
            if (!node.components || !Array.isArray(node.components)) {
                console.warn('   ⚠️ 节点没有components数组');
                return;
            }
            
            // 获取节点的model组件（从数组中查找）
            const modelComponent = node.components.find(c => c.type === 'model');
            if (!modelComponent) {
                console.warn('   ⚠️ 节点没有model组件，跳过保存');
                console.warn('   - 当前components:', node.components);
                return;
            }
            // 初始化meshMaterials对象（如果不存在）
            if (!modelComponent.meshMaterials) {
                modelComponent.meshMaterials = {};
            }
            
            // ✅ 新架构：直接保存材质名（key是meshName，value是materialName）
            const meshName = meshObject.name || 'Mesh';
            modelComponent.meshMaterials[meshName] = materialName;
            // ⭐ 重要：触发场景保存事件，将内存中的数据写入nodes.json
            this.notifyTreeChanged();
            
            // 给一点时间让保存完成
            await new Promise(resolve => setTimeout(resolve, 100));
        } catch (error) {
            console.error('   ❌ 保存材质绑定失败:', error);
            console.error('   - 错误堆栈:', error.stack);
            // 不抛出错误，避免影响材质创建流程
        }
    }
    
    /**
     * 从材质数据创建Three.js材质对象
     * @param {Object} materialData - 材质数据
     * @returns {THREE.Material} Three.js材质对象
     */
    createThreeMaterialFromData(materialData) {
        const MaterialClass = THREE[materialData.type] || THREE.MeshStandardMaterial;
        
        const params = {
            name: materialData.name || 'Material',
            color: new THREE.Color(materialData.color || '#ffffff'),
            opacity: materialData.opacity !== undefined ? materialData.opacity : 1.0,
            // 🔧 修复：透明相关参数 - 关键修复！
            transparent: materialData.transparent !== undefined ? materialData.transparent : false,
            alphaTest: materialData.alphaTest !== undefined ? materialData.alphaTest : 0,
            depthWrite: materialData.depthWrite !== undefined ? materialData.depthWrite : true,
            depthTest: materialData.depthTest !== undefined ? materialData.depthTest : true,
            side: materialData.doubleSided ? THREE.DoubleSide : THREE.FrontSide
        };
        
        // 根据材质类型添加特定参数
        if (materialData.type === 'MeshStandardMaterial' || materialData.type === 'MeshPhysicalMaterial') {
            params.metalness = materialData.metalness !== undefined ? materialData.metalness : 0.5;
            params.roughness = materialData.roughness !== undefined ? materialData.roughness : 0.5;
            params.emissive = new THREE.Color(materialData.emissive || '#000000');
            params.emissiveIntensity = materialData.emissiveIntensity !== undefined ? materialData.emissiveIntensity : 0;
            
            // ⭐ MeshPhysicalMaterial 特有参数
            if (materialData.type === 'MeshPhysicalMaterial') {
                params.clearcoat = materialData.clearcoat !== undefined ? materialData.clearcoat : 0;
                params.clearcoatRoughness = materialData.clearcoatRoughness !== undefined ? materialData.clearcoatRoughness : 0;
                params.reflectivity = materialData.reflectivity !== undefined ? materialData.reflectivity : 0.5;
                params.sheen = materialData.sheen !== undefined ? materialData.sheen : 0;
                params.transmission = materialData.transmission !== undefined ? materialData.transmission : 0;
                params.thickness = materialData.thickness !== undefined ? materialData.thickness : 0;
                params.ior = materialData.ior !== undefined ? materialData.ior : 1.5;
            }
        } else if (materialData.type === 'MeshPhongMaterial') {
            params.shininess = materialData.shininess !== undefined ? materialData.shininess : 30;
            params.emissive = new THREE.Color(materialData.emissive || '#000000');
            params.specular = new THREE.Color(materialData.specular || '#111111');
        } else if (materialData.type === 'MeshLambertMaterial') {
            params.emissive = new THREE.Color(materialData.emissive || '#000000');
        }
        
        const material = new MaterialClass(params);
        
        // ⭐ 应用贴图（从临时存储的贴图引用）
        if (materialData._textures) {
            const textureProperties = ['map', 'normalMap', 'bumpMap', 'aoMap', 'emissiveMap', 
                                       'metalnessMap', 'roughnessMap', 'specularMap', 'displacementMap'];
            textureProperties.forEach(prop => {
                if (materialData._textures[prop]) {
                    material[prop] = materialData._textures[prop];
                }
            });
        }
        
        // ⭐ 从URL加载纹理贴图
        const textureLoader = new THREE.TextureLoader();
        const backendUrl = window.APP_CONFIG?.backendUrl || window.location.origin;
        
        // 基础颜色贴图
        if (materialData.map) {
            textureLoader.load(
                `${backendUrl}${materialData.map}`,
                (texture) => {
                    texture.colorSpace = THREE.SRGBColorSpace;
                    
                    // 🔧 修复模糊问题：设置高质量纹理过滤
                    texture.generateMipmaps = true;
                    texture.minFilter = THREE.LinearMipmapLinearFilter;
                    texture.magFilter = THREE.LinearFilter;
                    const renderer = window.manager?.renderer;
                    const maxAnisotropy = renderer ? renderer.capabilities.getMaxAnisotropy() : 16;
                    texture.anisotropy = maxAnisotropy;
                    texture.needsUpdate = true;
                    
                    material.map = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载基础颜色贴图失败:', error)
            );
        }
        
        // 法线贴图
        if (materialData.normalMap) {
            textureLoader.load(
                `${backendUrl}${materialData.normalMap}`,
                (texture) => {
                    // 🔧 修复模糊问题：设置高质量纹理过滤
                    texture.generateMipmaps = true;
                    texture.minFilter = THREE.LinearMipmapLinearFilter;
                    texture.magFilter = THREE.LinearFilter;
                    const renderer = window.manager?.renderer;
                    const maxAnisotropy = renderer ? renderer.capabilities.getMaxAnisotropy() : 16;
                    texture.anisotropy = maxAnisotropy;
                    texture.needsUpdate = true;
                    
                    material.normalMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载法线贴图失败:', error)
            );
        }
        
        // 凹凸贴图
        if (materialData.bumpMap) {
            textureLoader.load(
                `${backendUrl}${materialData.bumpMap}`,
                (texture) => {
                    material.bumpMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载凹凸贴图失败:', error)
            );
        }
        
        // AO贴图
        if (materialData.aoMap) {
            textureLoader.load(
                `${backendUrl}${materialData.aoMap}`,
                (texture) => {
                    material.aoMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载AO贴图失败:', error)
            );
        }
        
        // 金属度贴图
        if (materialData.metalnessMap && material.metalnessMap !== undefined) {
            textureLoader.load(
                `${backendUrl}${materialData.metalnessMap}`,
                (texture) => {
                    material.metalnessMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载金属度贴图失败:', error)
            );
        }
        
        // 粗糙度贴图
        if (materialData.roughnessMap && material.roughnessMap !== undefined) {
            textureLoader.load(
                `${backendUrl}${materialData.roughnessMap}`,
                (texture) => {
                    material.roughnessMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载粗糙度贴图失败:', error)
            );
        }
        
        // 自发光贴图
        if (materialData.emissiveMap && material.emissiveMap !== undefined) {
            textureLoader.load(
                `${backendUrl}${materialData.emissiveMap}`,
                (texture) => {
                    texture.colorSpace = THREE.SRGBColorSpace;
                    material.emissiveMap = texture;
                    material.needsUpdate = true;
                    // 触发渲染更新
                    if (window.manager && window.manager.render) {
                        window.manager.render();
                    }
                },
                undefined,
                (error) => console.warn('加载自发光贴图失败:', error)
            );
        }
        
        // ⭐ 应用贴图强度参数
        if (materialData.aoMapIntensity !== undefined) {
            material.aoMapIntensity = materialData.aoMapIntensity;
        }
        if (materialData.bumpScale !== undefined) {
            material.bumpScale = materialData.bumpScale;
        }
        if (materialData.normalScaleX !== undefined && materialData.normalScaleY !== undefined) {
            material.normalScale = new THREE.Vector2(materialData.normalScaleX, materialData.normalScaleY);
        }
        if (materialData.displacementScale !== undefined) {
            material.displacementScale = materialData.displacementScale;
        }
        if (materialData.displacementBias !== undefined) {
            material.displacementBias = materialData.displacementBias;
        }
        return material;
    }
    
    /**
     * 清理节点及其子节点的材质引用
     */
    async removeMaterialReferencesForNode(node, sceneId) {
        if (!node || !window.materialEditorPanel) return;
        
        // 清理当前节点的材质引用
        if (node.object3D) {
            await this.removeMaterialReferencesForObject(node.object3D, sceneId, node.id);
        }
        
        // 递归清理子节点的材质引用
        if (node.children && node.children.length > 0) {
            for (const childNode of node.children) {
                await this.removeMaterialReferencesForNode(childNode, sceneId);
            }
        }
    }
    
    /**
     * 清理Three.js对象及其子对象的材质引用
     */
    async removeMaterialReferencesForObject(object, sceneId, nodeId) {
        if (!object) return;
        
        // 如果是mesh，清理材质引用
        if (object.isMesh && object.material) {
            if (Array.isArray(object.material)) {
                for (const material of object.material) {
                    const materialId = material.userData?.materialId;
                    if (materialId && window.materialEditorPanel.removeMaterialUsage) {
                        await window.materialEditorPanel.removeMaterialUsage(materialId, sceneId, nodeId, object.uuid);
                        console.log(`   🔄 [Scene Tree] 移除材质引用: ${materialId} (mesh: ${object.name}, node: ${nodeId})`);
                    }
                }
            } else {
                const materialId = object.material.userData?.materialId;
                if (materialId && window.materialEditorPanel.removeMaterialUsage) {
                    await window.materialEditorPanel.removeMaterialUsage(materialId, sceneId, nodeId, object.uuid);
                    console.log(`   🔄 [Scene Tree] 移除材质引用: ${materialId} (mesh: ${object.name}, node: ${nodeId})`);
                }
            }
        }
        
        // 递归清理子对象的材质引用
        if (object.children && object.children.length > 0) {
            for (const childObj of object.children) {
                await this.removeMaterialReferencesForObject(childObj, sceneId, nodeId);
            }
        }
    }
}

/**
 * 创建场景树UI实例
 * @param {HTMLElement} containerElement - 容器元素
 * @param {SceneTreeManager} treeManager - 树管理器
 * @param {string} mode - 显示模式 ('edit' 或 'presentation')
 */
export function createSceneTreeUI(containerElement, treeManager, mode = 'edit') {
    return new SceneTreeUI(containerElement, treeManager, mode);
}

